9.1.3.6.2. Cifrado de bloques¶
Mediante esta técnica el software hace de intermediario entre los bloques físicos y los bloques de un dispositivo virtual cifrando en las escrituras y descifrando en las lecturas.
En consecuencia:
Ciframos un dispositivo de bloques entero.
Como el cifrado es independiente del sistema de archivos, se puede utilizar cualquier sistema de archivos.
Permite no sólo el cifrado de datos, sino el cifrado del sistema operativo de arranque, preparando convenientemente el sistema (caso que no abordaremos aquí, pero que puede consultarse, por ejemplo, en un artículo de la wiki de Archlinux).
Utilizaremos LUKS y abordaremos el caso más sencillo de querer cifrar una partición física, para lo cual debemos primero instalar el software de cifrado:
# apt install cryptsetup
Operativa manual
Lo primero es mapear una partición física[1] (p.e. /dev/sda6
) sobre
un dispositivo virtual:
# cryptsetup -y -v luksFormat /dev/sda6 # Requerirá una contraseña
# cryptsetup open /dev/sda6 cifrado # Debemos proporcionar la contraseña
Esto generará el dispositivo virtual de bloques /dev/mapper/cifrado
,
sobre el cual podemos actuar como si se tratara de un dispositivo físico, o
sea:
# mkfs.ext4 -L DATOSECRETOS /dev/mapper/cifrado
# mount /dev/mapper/cifrado /mnt
Si en algún momento quisiéramos desmontar todo:
# umount /mnt
# cryptsetup close cifrado
Operativa automatizada
Que el administrador deba llevar a cabo estas operaciones cada vez que se
arranca el sistema, no es algo operativo. Para semiautomatizar el montaje
durante el arranque podemos añadir la asociación entre el dispositivo físico y
el virtual en /etc/crypttab
:
# echo "cifrado /dev/sda6 none" >> /etc/crypttab
y la asociación entre el dispositivo virtual y el punto de montaje en
/etc/fstab
:
# echo "/dev/mapper/cifrado /mnt ext4 defaults 0 0" >> /etc/fstab
El montaje será semiautomático, porque durante el proceso de arranque deberemos digitalizar la contraseña. Es posible, también, en vez de que la clave sea interactiva, guardarla en un archivo. Es más, LUKS dispone de ocho slots para almacenar claves alternativas. Ahora mismo sólo habría una:
# cryptsetup luksDump /dev/sda6
LUKS header information
Version: 2
Epoch: 8
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: e26d3cf8-20a7-422f-ac8f-83340e63725f
Label: (no label)
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2i
Time cost: 4
Memory: 98948
Threads: 1
Salt: a0 a1 57 4c 30 6a af e5 de 76 d5 d8 a9 f0 11 b7
ac b5 c6 90 d0 1d 4e 92 4d 1c 4b b5 4c 07 97 70
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:58048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 39337
Salt: 2b c9 51 10 c7 29 4b 63 35 a4 83 63 bc 36 46 2f
49 92 af dd 32 a8 7c 9d 19 08 51 80 1b 58 6f 56
Digest: 0c 52 b0 1d 8c 80 2e 6b 45 0a c8 ac 4a b2 e9 a2
f4 bf 81 e6 5a 00 c4 42 af 10 21 9c 3a 92 fe 6c
con lo que podemos añadir al mismo sistema otra clave que esté en un archivo. Para ello, vamos primero a generar esa clave, constituida por 512 bytes totalmente aleatorios:
# dd < /dev/urandom > /root/luks.key bs=512 count=1
que, podemos consultar en formato hexadecimal, así:
# od -v -An -tx1 /root/luks.key # Consultamos la clave
dc 12 ae d8 2c b5 4e 12 56 a9 35 b4 5f a6 29 b9
[...]
Con la clave ya en el archivo /root/luks.key
, podemos añadirla a un
slot:
# cryptsetup luksAddKey /dev/sda6 /root/luks.key
# cryptsetup luksDump /dev/sda6
[...]
Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2i
Time cost: 4
Memory: 98948
Threads: 1
Salt: a0 a1 57 4c 30 6a af e5 de 76 d5 d8 a9 f0 11 b7
ac b5 c6 90 d0 1d 4e 92 4d 1c 4b b5 4c 07 97 70
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
1: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2i
Time cost: 4
Memory: 100952
Threads: 1
Salt: b1 63 a9 24 aa cc f5 9c b4 6c 8a 8b 27 7a cb 2c
72 cd f8 d9 68 b9 1b f4 43 c7 d6 b5 20 81 47 c5
AF stripes: 4000
AF hash: sha256
Area offset:290816 [bytes]
Area length:258048 [bytes]
Digest ID: 0
[...]
Por último, si en /etc/crypttab
modificamos la línea para que se use el
archivo:
cifrado /dev/sda6 /root/luks.key
durante el arranque no se pedirá ninguna clave y el sistema se encontrará montado al acabar la secuencia.
Advertencia
Ahora bien, ¿para qué ciframos una partición si dejamos la clave para su descifrado en un archivo de otra partición sin cifrar?
Lo interesante de lo anterior es, simplemente, comprobar que se puede guardar la clave en un archivo y usarlo para no tener que escribirla interactivamente. Y ello es útil, si almacenamos el archivo en un dispositivo externo como un pincho USB que procuremos retirar y llevarnos lejos de la máquina cuando no la usemos. Además, es conveniente ocultar ese archivo para que pase desapercibido si alguien se hace con nuestro pincho. A este respecto, lo más juicioso es guardar los 512 bytes de la clave en algún espacio libre del pincho USB y ajeno a los sistemas de archivos que pueda haber en él:
Si el particionado es DOS, podemos utilizar los últimos 512 bytes del espacio entre el MBR y la primera partición, ya que al principio de ese espacio puede haber código de un gestor de arranque como GRUB.
Si el particionado es GPT, podemos utilizar los últimos 512 bytes del espacio que se reserva para definir particiones, ya que es bastante improbable que en el pincho hayamos creado más de 124 particiones.
Pongamos este segundo caso de ejemplo. En un disco GPT:
El primer sector es un MBR ficticio (512B)
El segundo sector es la cabecera GPT (512B)
A continuación hay espacio para 128 definiciones de particiones cada una de las cuales ocupa 128 bytes (16KiB).
En consecuencia el comienzo del disco ocupa 17KiB o lo que es lo mismo 34 sectores, así que podemos ocupar el sector 34 para almacenar nuestra clave, con el único costo de que "sólo" podremos definir 124 particiones, lo cual, ciertamente, no parece ningún problema.
Supongamos que el pincho se encuentra en /dev/sdb
[2]:
# gdisk -l /dev/sdb
[...]
Number Start (sector) End (sector) Size Code Name
1 416 103003 50.1 MiB EF00 EFI System Partition
2 103008 30719966 14.6 GiB 0700 Microsoft basic data
Vamos a crear una clave aleatoria de 512 bytes directamente sobre su sector 34:
# dd < /dev/urandom > /dev/sdb bs=512 count=1 seek=33
y, creada, la añadimos a un slot:
# { echo "secreto" ; dd < /dev/sdb bs=512 count=1 skip=33; } | cryptsetup luksAddKey /dev/sda6 -
donde «secreto» es la contraseña que introdujimos al crear el dispositivo cifrado y que nos servía para hacer el montaje interactivo. Añadida esta clave, podemos probar si funciona del siguiente modo:
# dd < /dev/sdb bs=512 count=1 skip=33 | cryptsetup open /dev/sda6 cifrado --key-file=-
que debe generar el dispositivo virtual y, si continua la línea en
/etc/fstab
, montarnos directamente la partición sobre /srv
. Ya
tenemos la mitad del trabajo hecho, ya que aún falta que al arrancar el sistema
busque el dispositivo, lo monte y lleve a cabo justamente esta operación.
Para ello, debemos crear una regla para udev, que al detectar el dispositivo USB lance un script:
# cat > /etc/udev/rules.d/70-usb.rules
SUBSYSTEMS=="usb", ACTION=="add", ATTRS{idVendor}=="abcd", ATTRS{idProduct}=="1234", \
KERNEL=="sd?", SYMLINK+="usbkey", RUN+="/usr/local/bin/unlock.sh"
La regla identifica el dispositivo en el que hemos guardado la clave a través de su idVendor e idProduct que se pueden consultar fácilmente al hacer:
$ lsusb
[...]
Bus 002 Device 002: ID abcd:1234 Unknown
[...]
Además, aprovechamos la regla para añadir un enlace simbólico /dev/usbkey
que apunte
al dispositivo. Con este nombre podremos referirnos al dispositivo dentro del script:
#!/bin/sh
RT="/dev/sda6"
DEVICE="/dev/usbkey"
ENCVOL="cifrado"
MOUNTP="/srv"
{
until [ -b "$PART" ]; do sleep .5; done
dd < "$DEVICE" bs=512 count=1 skip=33 | \
cryptsetup open "$PART" "$ENCVOL" --key-file=-
} &
Por último, en /etc/crypttab
no debe existir referencia alguna, ya
que es el script el que realiza la operación de crear el dispositivo cifrado.
En /etc/fstab
, sí podemos dejar la línea, pero añadiendo la opción
nofail, para que no falle el montaje y pare el arranque en caso de que no se
encuentre el pincho:
/dev/mapper/cifrado /srv ext4 defaults,nofail 0 0
Nota
Esta estrategia está tomada de esta entrada de /dev/blog y sólo es válida si se cifra una partición de datos y no la partición del sistema. Si se lleva a cabo el cifrado del sistema, es necesario recurrir a otra estrategia totalmente distinta basada en manipular la imagen initramfs.
Notas al pie