DevSecOps

3 set, 2015

Criando volumes encriptados com LUKS no GNU/Linux

Publicidade

Esses dias eu precisei montar um volume encriptado para gravar algumas informações que achava interessante ficarem isoladas do restante do disco. Nada de teorias de conspiração (vocês sabiam que tenho interesse muito grande por ufologia? posso contar essa história qualquer dia ..) nem nenhum material de alguma bizarrice pornô, apenas algumas coisas que às vezes aparecem que não acho interessante gravar como de costume no Evernote ou armazenar no Google Drive. Criar o volume é um dos passos – fáceis – mas é muito importante outro passo que a gente sempre esquece. Importante: use esses procedimentos por sua conta e risco!.

Criando o volume

Primeiro vamos criar o volume usando o LUKS, que é uma especificação para encriptar discos que apesar de originalmente destinada para o GNU/Linux, roda até em sistemas com windows.

Para criar o volume, temos primeiro que estipular um tamanho bom para ele. Para nosso exemplo, vamos criar um volume com 100 Mb de tamanho, criando um novo arquivo com esse tamanho através do utilitário dd, no diretório de sua preferência (aqui eu vou usar o /tmp para o exemplo, mas nunca use esse diretório pois distribuições como o Ubuntu apagam o conteúdo do danado quando são reiniciadas):

dd if=/dev/zero of=secret.img bs=1M count=100

Explicando um pouco o comando:

  1. Foi utilizado como input (através de if) dos bytes o device /dev/zero, o que vai preencher o volume com um monte de zeros. Se você não estiver com pressa e tiver várias coisas rodando no computador, pode utilizar o /dev/random, que vai deixar o volume mais seguro ainda).
  2. O output do comando foi para o arquivo secret.img, que pode ser dado qualquer nome (e extensão) que você quiser (gemeas_siamesas_e_bode.img, por exemplo, se você for uma pessoa bem pervertida e ingênua).
  3. O block size, que são os tamanhos dos blocos a serem alocados, foi indicado como sendo 1 Mb (bs=1M).
  4. O total de blocos foi especificado como 100 (através de count=100), ou seja, se temos blocos de 1 Mb e queremos 100 blocos, vamos ter um arquivo de 100 Mb.

Esse comando deve rodar bem rápido e retornar algo similar à isso:

100+0 registros de entrada
100+0 registros de saída
104857600 bytes (105 MB) copiados, 0,0672096 s, 1,6 GB/s

Montando o volume como um dispositivo de bloco

Agora temos que “montar” esse arquivo criado como se fosse um dispositivo de blocos. Para isso, vamos utilizar o comando losetup, mas antes de montar, vamos ver quais dispositivos de blocos que temos disponíveis (reparem que vamos começar a utilizar o sudo para executar alguns comandos, alguns não precisam mas já fica garantido que se precisar, já tem autoridade):

$ sudo losetup -a
$  

Aqui o resultado foi vazio, indicando que não existem nenhum dispositivos do tipo montados. Quando é vazio, podemos começar a montar nossos dispositivos a partir do 0, aproveitando para listar novamente:

$ sudo losetup /dev/loop0 secret.img

$ sudo losetup -a
/dev/loop0: [2049]:1967672 (/tmp/secret.img)

Formatando o volume

Vamos formatar o volume indicando que deve usar o LUKS, com o utilitário cryptsetup:

$ sudo cryptsetup luksFormat /dev/loop0

WARNING!
========
Isto irá sobrescrever os arquivos em /dev/loop0 definitivamente.

Are you sure? (Type uppercase yes): YES
Informe a frase secreta: 
Verify passphrase: 

Ali é exibida uma parte muito importante do processo: a senha do volume. Se você perder a senha, já era, seus dados não vão estar mais acessíveis a não ser que você utilize uma senha muito fácil que possa ser quebrada por força bruta, mas senhas simples para um volume como esse não é o caso, não é mesmo? Utilize uma senha boa e que possa ser lembrada.

Abrindo o volume

Temos agora que abrir o volume encriptado, dando um nome à ele (eu costumo utilizar o mesmo nome do arquivo criado, sem a extensão, mas fica ao critério de cada um):

$ sudo cryptsetup luksOpen /dev/loop0 secret
Informe a frase secreta para /tmp/secret.img:

Criando o sistema de arquivos

Precisamos montar um sistema de arquivos no volume já aberto. Vamos utilizar o ext4 como sistema de arquivos e formatar utilizando o mkfs.ext4 (reparem que aqui utilizamos o mapper):

$ sudo mkfs.ext4 /dev/mapper/secret

mke2fs 1.42.12 (29-Aug-2014)
Creating filesystem with 100352 1k blocks and 25168 inodes
Filesystem UUID: 5733fdf2-9ef9-444e-9da3-043f95943c54
Cópias de segurança de superblocos gravadas em blocos: 
    8193, 24577, 40961, 57345, 73729

Allocating group tables: pronto                            
Gravando tabelas inode: pronto                            
Creating journal (4096 blocks): concluído
Escrevendo superblocos e informações de contabilidade de sistema de arquivos:  0concluído

Montando o sistema de arquivos

Precisamos de algum local no sistema de arquivos atual para montar o volume já criado, formatado e com sistema de arquivos. Vamos criar um diretório novo e montar:

$ mkdir secret

$ sudo mount /dev/mapper/secret secret  

Dando permissões no sistema de arquivos

O sistema de arquivos foi criado com permissões apenas para o usuário root. Vamos corrigir isso entrando dentro do sistema de arquivos montado, ajustando as permissões para o usuário corrente e criando um arquivo novo para ver se ficou tudo ok:

$ cd secret/

[secret] $ ls
total 33K
drwxr-xr-x  3 root root 1,0K Jun 27 09:47 .
drwxrwxrwt 22 root root  20K Jun 27 09:58 ..
drwx------  2 root root  12K Jun 27 09:47 lost+found

[secret] $ sudo chown -Rv taq.taq .
alterado o dono de “./lost+found” de root:root para taq:taq
alterado o dono de “.” de root:root para taq:taq

[secret] $ echo "oi" > teste.txt
[secret] $ cat teste.txt
oi

Fechando tudo

Agora que tudo o que precisávamos para o volume está feito, podemos “fechar o boteco” (vejam que inicialmente eu estava dentro do diretório do volume montado, por isso que utilizei o cd para sair):

[secret] $ cd ..

$ sudo umount secret

$ sudo cryptsetup luksClose secret

$ sudo losetup -d /dev/loop0

$ sudo losetup -a

Como podemos ver no comando final, não existe mais nenhum dispositivo de blocos montado. Yay.

Extras muito importantes

Tudo lindo e maravilhoso, mas aí você, como eu, insere uma senha “hacker-muito-macho-nunca-vou-esquecer-essa-bodega” e … esquece a dita cuja. Ou pior, você tem tudo certinho mas por alguma infelicidade do sistema de arquivos do seu disco rígido, o volume encriptado é corrompido, e aí?

Antes de acontecer alguma situação nada agradável como essas, podemos garantir algumas coisas.

Adicionando uma senha extra

O Luks permite que tenhamos até 8 senhas (!!!) para o volume criado. Vamos dar uma olhada no cabeçalho do arquivo criado:

$ sudo cryptsetup luksDump secret.img 
LUKS header information for secret.img

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha1
Payload offset: 4096
MK bits:        256
MK digest:      22 a2 74 61 50 61 7a 36 d6 af 70 be ce ee 33 fe d1 af 4c c8 
MK salt:        7b 73 18 d3 20 0b 75 ad 9f 7d c4 f1 56 2d f0 10 
                6e bd fe e5 e0 e9 8f 9d 9a 78 17 57 1c 9f 63 7d 
MK iterations:  108000
UUID:           8f6d3b69-493a-4757-910b-5eba39b8a028

Key Slot 0: ENABLED
    Iterations:             432431
    Salt:                   23 e9 5d f7 a4 e1 6d 6a 00 ba 33 d5 62 67 42 ab 
                            fb c0 4c 20 43 be 4b cc ea 63 38 fe 75 b3 e6 cb 
    Key material offset:    8
    AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

Podemos ver ali que o slot 0 está sendo utilizado, que é onde inserimos a senha quando formatamos o volume. Vamos pedir para adicionar mais uma senha:

$ sudo cryptsetup luksAddKey --key-slot 1 secret.img 
Enter any existing passphrase: 
Digite nova frase secreta para porta: 

Como podemos ver, alguma das senhas já armazenadas é requisitada quando pedimos para adicionar uma senha nova, então faça isso logo após criar o volume com a senha inicial! Dando uma olhada novamente no cabeçalho:

$ sudo cryptsetup luksDump secret.img 
LUKS header information for secret.img

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha1
Payload offset: 4096
MK bits:        256
MK digest:      22 a2 74 61 50 61 7a 36 d6 af 70 be ce ee 33 fe d1 af 4c c8 
MK salt:        7b 73 18 d3 20 0b 75 ad 9f 7d c4 f1 56 2d f0 10 
                6e bd fe e5 e0 e9 8f 9d 9a 78 17 57 1c 9f 63 7d 
MK iterations:  108000
UUID:           8f6d3b69-493a-4757-910b-5eba39b8a028

Key Slot 0: ENABLED
    Iterations:             432431
    Salt:                   23 e9 5d f7 a4 e1 6d 6a 00 ba 33 d5 62 67 42 ab 
                            fb c0 4c 20 43 be 4b cc ea 63 38 fe 75 b3 e6 cb 
    Key material offset:    8
    AF stripes:             4000
Key Slot 1: ENABLED
    Iterations:             407642
    Salt:                   3d c0 ea 6c df f3 f0 37 b0 0e df b0 24 e9 ce 97 
                            9c e5 38 75 ba 84 68 91 30 91 19 ae f3 21 51 86 
    Key material offset:    264
    AF stripes:             4000
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED

Perfeito, o slot 1 foi alocado. Vamos tentar abrir o volume agora com essa nova senha (fica a dica para a sequência de comandos, menos o ls e o cat, lógico, para a montagem dos volumes, utilizados ali somente para verificar se está tudo ok):

$ sudo losetup /dev/loop0 secret.img 

$ sudo cryptsetup luksOpen /dev/loop0 secret
Informe a frase secreta para /tmp/secret.img: 

$ sudo mount /dev/mapper/secret secret

$ ls secret
total 34K
drwxr-xr-x  3 taq  taq  1,0K Jun 27 10:02 .
drwxrwxrwt 22 root root  20K Jun 27 10:18 ..
drwx------  2 taq  taq   12K Jun 27 09:47 lost+found
-rw-rw-r--  1 taq  taq     3 Jun 27 10:02 teste.txt

$ cat secret/teste.txt 
oi

Senha extra funcionando corretamente.

Fazendo um backup do cabeçalho

Aí o seu disco rígido (interno, externo, pendrive ou onde seja que você armazenou o volume) dá algum tipo de problema e corrompe o seu arquivo. Vamos voltar no tempo e criar alguns resguardos em relação à isso. Antes de mais nada, vamos executar um teste para verificar se o cabeçalho do volume está ok:

$ sudo cryptsetup -v isLuks secret.img 
Comando excutado com sucesso.

Aparentemente, tudo ok. Agora vamos fazer o backup do cabeçalho para um arquivo:

$ sudo cryptsetup luksHeaderBackup secret.img --header-backup-file secret.header

Isso gera um arquivo chamado secret.header que pode ser mais tarde utilizado para recuperar o cabeçalho do volume. Armazene esse cabeçalho em um local seguro!

Removendo o cabeçalho

Mas que diabos, se logo ali acima estamos tentando dar um jeito de preservar o cabeçalho, para que remover o dito cujo? Simples: para que ninguém saiba que aquele volume é um volume LUKS. 🙂

Um cabeçalho LUKS é facilmente identificável com os bytes logo no começo do volume:

$ hexdump -C secret.img | less
00000000  4c 55 4b 53 ba be 00 01  61 65 73 00 00 00 00 00  |LUKS....aes.....|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000020  00 00 00 00 00 00 00 00  78 74 73 2d 70 6c 61 69  |........xts-plai|
...

Podemos remover e depois restaurar com a cópia que fizemos acima. Para isso vamos apagar os primeiros bytes do arquivo, no tamanho do cabeçalho que foi salvo anteriormente, verificado no primeiro comando:

$ sudo wc -c secret.header | cut -f1 -d' '
1049600

$ dd conv=notrunc if=/dev/zero of=secret.img bs=1 count=1049600
1049600+0 registros de entrada
1049600+0 registros de saída
1049600 bytes (1,0 MB) copiados, 0,958486 s, 1,1 MB/s

Verificando novamente se é um volume LUKS válido:

$ sudo cryptsetup -v isLuks secret.img 
O dispositivo secret.img não é um dispositivo LUKS válido.
Falha no comando com código 22: O dispositivo secret.img não é um dispositivo LUKS válido

Restaurando o cabeçalho

Agora vamos restaurar o cabeçalho:

$ sudo cryptsetup luksHeaderRestore secret.img --header-backup-file secret.header 
[sudo] password for taq: 

WARNING!
========
Dispositivo secret.img não contém um cabeçalho LUKS. Substituindo o cabeçalho pode destruir os dados no dispositivo.

Are you sure? (Type uppercase yes): YES

Verificando novamente:

$ sudo cryptsetup -v isLuks secret.img 
Comando excutado com sucesso.

$ sudo losetup /dev/loop0 secret.img 

$ sudo cryptsetup luksOpen /dev/loop0 secret
Informe a frase secreta para /tmp/secret.img: 

$ sudo mount /dev/mapper/secret secret

$ ls secret
total 34K
drwxr-xr-x  3 taq  taq  1,0K Jun 27 10:02 .
drwxrwxrwt 22 root root  20K Jun 27 12:29 ..
drwx------  2 taq  taq   12K Jun 27 09:47 lost+found
-rw-rw-r--  1 taq  taq     3 Jun 27 10:02 teste.txt

$ cat secret/teste.txt 
oi