Archivo por meses: enero 2015

Cifrando discos, particiones o ficheros con LUKS

Uno de los mecanismos más eficaces para proteger nuestra información es el cifrado. Hoy no se me pasa por la cabeza tener un portátil sin el disco cifrado. Lo grave no sería la pérdida física del mismo, sino la de la información que lleve y en las manos que pueda acabar. Pero esto no es sólo aplicable a portátiles, discos USB o pendrives con información sensible también deberían estar cifrados para evitar que dicha información sea accesible por terceros no autorizados.

En GNU/Linux tenemos múltiples opciones a la hora de cifrar nuestra información. GPG sobre ficheros, eCryptfsEncFS sobre directorios, TrueCrypt o dm-crypt sobre dispositivos,  loop-AES para ficheros loop, etc. De todas las opciones mi preferida es LUKS (Linux Unified Key Setup), que podemos usar sobre discos, particiones, volúmenes lógicos (LVs) o ficheros loop. Entre sus ventajas están: su sencillez de uso, incluido en el propio kernel y la capacidad de asignar, cambiar y revocar varias claves para un mismo dispositivo.

La instalación de muchas distribuciones actuales hace muy sencillo incorporar el cifrado del sistema completo desde el principio. Mi recomendación en un portátil es: crear una pequeña partición para /boot (que no irá cifrada) y dejar el resto del disco para ser cifrado con LUKS. Sobre dicho cifrado crear un PV para LVM y  todo lo que vaya sobre el LVM ya estará cifrado.

Pero en la entrada de hoy veremos como usar LUKS en un sistema que ya está corriendo, por ejemplo para cifrar un nuevo volumen lógico, un fichero loop donde guardar información sensible, o un dispositivo USB donde realizar backups.

Ingredientes

Tener instalado el paquete cryptsetup (también llamado cryptsetup-luks en algunas distribuciones). Tener un dispositivo sin usar (su información será reescrita al cifrarlo inicialmente), por ejemplo /dev/sdc, /dev/vgpruebas/cifrado, /dev/sdb2,… En el caso de querer user un fichero (loop) podemos crearlo con este comando:

## En este ejemplo 50 bloques de 1MB ~ 50MB
## Aunque es posible crecer el fichero posteriormente es
## algo enrevesado, mejor afinar con el tamaño que necesitemos
## Podemos usar /dev/zero como origen de datos en la creación
## del fichero también, pero facilitaría un posible criptoanálisis
$ dd if=/dev/urandom of=fichero_cifrado bs=1M count=50

Inicialización del cifrado

El primer paso será dar el formato LUKS al dispositivo. Para ello usaremos el comando cryptsetup con argumento luksFormat. Entre las diversas opciones que podemos especificar está el algoritmo de cifrado, el tamaño de la clave o la función hash (resumen) o el fichero clave.

Veamos algunos ejemplos:

## Cifrar el fichero creado en el ejemplo anterior con una
## contraseña, pidiéndola dos veces (para confirmar que
## se tecleó correctamente). Usando valores por defecto
## para el cifrado:
$ cryptsetup --verify-passphrase luksFormat fichero_cifrado

## Podemos averiguar el algoritmo, tamaño de clave y función
## hash que se usan por defecto con este comando:
$ cryptsetup --help | grep LUKS.*Key
 LUKS1: aes-xts-plain64, 
 Key: 256 bits, 
 LUKS header hashing: sha1, 
 RNG: /dev/urandom

## Si los valores por defecto no nos convencen, podemos
## especificar otros, por ejemplo un tamaño de clave de
## cifrado mayor (de 256 bits) y una función hash que no
## haya sido declarada insegura (como es el caso de SHA1):
cryptsetup --hash=sha256 --key-size=512 --verify-passphrase \
 luksFormat fichero_cifrado

## Cifrar un dispositivo (p.e. un disco USB) usando un fichero
## como contraseña.
## Primero creamos el fichero de contraseña (podemos hacerlo
## a mano, o usar /dev/random o /dev/urandom para rellenarlo)
$ dd if=/dev/urandom of=mi_secreto bs=1M count=1

## Un megabyte de contraseña!
## ¿Qué tamaño máximo de contraseña (tecleada o en fichero)
## podemos usar? El siguiente comando lo aclara:
$ cryptsetup --help | grep Maximum
   Maximum keyfile size: 8192kB,
   Maximum interactive passphrase length 512 (characters)
 
## Una vez tenemos el fichero de contraseña, podemos dar el
## formato LUKS usando éste, en vez de tecleando una contraseña
## de forma interactiva
## El siguiente comando lo ejecutamos como root, al tratarse
## de un dispositivo (/dev/sdc) y no un fichero de usuario:
# cryptsetup luksFormat /dev/sdc /path/al/fichero/mi_secreto
## o
# cryptsetup --key-file=/path/al/fichero/mi_secreto luksFormat /dev/sdc

## Por supuesto también podríamos modificar el tamaño de clave
## de cifrado o la función hash.

Clave de cifrado, contraseña y cabecera LUKS

Llegados a este punto debo (intentar) esclarecer algún término. Cuando damos formato LUKS a un dispositivo/fichero hablamos de dos términos similares, pero diferentes:

  • Contraseña. Ya sea una tecleada en el momento, o un fichero usado como tal, es la que nos permite acceder al dispositivo LUKS. Esta contraseña no es usada para cifrar los datos. De hecho, una de las ventajas de usar LUKS es que podemos usar varias contraseñas/ficheros contraseña para un mismo dispositivo. Más adelante daré un ejemplo.
  • Clave de cifrado. Esta clave se genera automáticamente cuando damos el formato LUKS al dispositivo. Se genera de forma aleatoria (por defecto usando /dev/urandom) y con el tamaño por defecto (256 bits) o el que se especifique con la opción –key-size. Si bien es posible especificar una clave de cifrado de forma manual (–master-key-file) no es recomendable hacerlo salvo que sepas exactamente que estás haciendo.

El formato LUKS se caracteriza por una cabecera que incluye la información del algoritmo de cifrado, tamaño de clave, contraseñas en uso, etc. Podemos consultar dicha cabecera (que no las contraseñas!) con el siguiente comando:

$ cryptsetup luksDump fichero_cifrado 
LUKS header information for fichero_cifrado

Version: 1
Cipher name: aes
Cipher mode: xts-plain64
Hash spec: sha256
Payload offset: 4096
MK bits: 512
MK digest: ca cb 7e f6 20 fa 42 8a 7e 0a 92 66 86 bd 20 46 77 28 a5 25 
MK salt: a1 e5 54 8d c2 4d db af 3d 72 73 4d f6 0b 9f b7 
 41 d7 46 31 ce dc f8 11 21 86 8c 22 d9 cf e5 ca 
MK iterations: 95125
UUID: d58132bd-ea6b-4879-aa73-c8d444300545

Key Slot 0: ENABLED
 Iterations: 378697
 Salt: 1a 54 1a cd 92 74 13 78 5d 72 f4 00 60 b4 69 85 
 c7 8a a9 fa 50 65 6b 32 f4 13 a4 e2 b6 3b c3 69 
 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

En este ejemplo vemos que se está usando AES como algoritmo de cifrado, que el tamaño de clave es de 512 bits, la función hash es SHA256 y que hay una contraseña (de las 8 posibles) en uno (Key Slot 0: ENABLED). El resto de posibles contraseñas no están establecidas (DISABLED).

Usando el dispositivo cifrado

Una vez tenemos el formato LUKS en el dispositivo, para acceder a los datos en claro habrá que «abrir el contenedor cifrado». Es decir, antes de poder usarlo (montarlo o formatearlo) hay que descifrarlo:

## Si vamos a abrir un fichero protegido con
## contraseña "tecleada":
# cryptsetup luksOpen fichero_cifrado dispositivo_descifrado

## Si el fichero o dispositivo está protegido con un fichero
## contraseña, se lo indicamos como opción:
#  cryptsetup --key-file=mi_secreto luksOpen /dev/sdc dispositivo_descifrado

## Unos comentarios sobre estos ejemplos:
## 1.- "dispositivo_descifrado" es el nombre que queremos para el
##     dispositivo que se creará trás ejecutar este comando
##     y que será el que ya usemos para formatear o montar de forma
##     normal
## 2.- Si la contraseña es válida, desde este momento podremos acceder
##     al dispositivo "en claro" como /dev/mapper/dispositivo_descifrado
## 3.- Estos comandos se ejecutan con el usuario "root" ya que crean
##     un dispositivo nuevo. (Sí, seguro que hay interfaces de usuario
##     que permiten estas tareas a un usuario corriente)

Por supuesto, la primera vez que lo abrimos lo más frecuente será formatearlo, como con cualquier dispositivo nuevo:

mkfs.ext4 /dev/mapper/dispositivo_descifrado

Desde ese momento, y después de abrirlo con «luksOpen«, simplemente lo montaremos como el resto de dispositivos de almacenamiento:

mount /dev/mapper/dispositivo_descifrado /media/mis_datos_secretos

Cerrar después de usar

Cuando ya no necesitemos acceso a los datos, y después de desmontar como con cualquier otro dispositivo de almacenamiento, debemos «cerrar» el acceso al dispositivo sin cifrar. O como decía Mamá – deja las cosas como las encontraste:

## Desmontar antes de cerrar el acceso
# umount /media/mis_datos_secretos
## Eliminar el acceso al dispositivo descifrado
# cryptsetup luksClose dispositivo_descifrado

¿Varias contraseñas?

Para terminar comentaré una de las características que más me gustan de LUKS y que en un principio puede sonar extraña: la capacidad de tener varias contraseñas/ficheros contraseña.

Insistir en que las contraseñas no son las que se usan para cifrar, eso se hace con la clave de cifrado, sino para dar acceso a ésta y poder abrir el dispositivo. Poder usar más de una (y ser capaces de revocarlas, cambiarlas o añadirlas) permite:

  • Tener una contraseña por usuario para un mismo dispositivo. De forma que cada uno sabe la suya y si un día se decide evitar el acceso de uno de ellos basta con eliminar su contraseña, lo que no afecta al resto de usuarios.
  • Tener una contraseña para nosotros (que tecleamos cuando queremos acceso al dispositivo) y tener un fichero contraseña para tareas automatizadas (por ejemplo backups). Yo tengo un disco USB donde se hacen backups de mi portátil de forma automática. Para no tener que teclear la contraseña (y estar delante del ordenador) cuando se realiza el backup, en el disco del portátil tengo un fichero contraseña que le permite descifrar el USB y realizar el backup. Por supuesto este fichero contraseña sólo puede leerlo el usuario root y el disco de mi portátil está cifrado. Pero ¿qué pasaría si el disco de mi portátil muere? Ya no tendría el fichero contraseña para descifrar el disco USB de backup. Estúpida situación ésta… Salvo que el USB con LUKS tiene una segunda contraseña (que puedo teclear) y que me permitiría acceder a él aunque el disco de mi portátil muriera.

Sobra decir que hay que tener sumo cuidado con los ficheros usados como contraseña, su acceso debería estar extremadamente limitado (permisos, acceso al dispositivo donde se almacenan, etc..).

¿Cómo gestionamos las contraseñas de un dispositivo con LUKS?

Como vimos anteriormente, podemos ver la información de la cabecera LUKS con el comando «cryptsetup luksDump DISPOSITIVO«. En el veremos los «slots» («contraseñas») que están en uso. Normalmente el slot-0 siempre lo está, porque es donde se guarda la contraseña inicial. Podemos añadir una nueva contraseña con el siguiente comando:

## Si queremos una contraseña "tecleada"
# cryptsetup luksAddKey /dev/sdc

## Primero nos pedirá una contraseña ya existente
## en alguno de los slots, si no hay contraseña
## sino "fichero contraseña" deberemos usar la
## opción --key-file:
# cryptsetup --key-file=/etc/mi_secreto luksAddKey /dev/sdc

## Si queremos añadir un "fichero contraseña"
# cryptsetup luksAddKey /dev/sdc /etc/mi_nuevo_secreto

## Al igual que antes, si no hay una contraseña en
## algún slot, sino que son todo ficheros contraseña
## le indicamos alguno de los actuales con --key-file
# cryptsetup --key-file=/etc/mi_secreto \
    luksAddKey /dev/sdc /etc/mi_nuevo_secreto

También podemos borrar o cambiar contraseñas (o ficheros contraseña) existentes:

## Para borrar un "slot" tenemos dos opciones:
## Teclear (o especificar el fichero contraseña
## después del nombre de dispositivo)
$ cryptsetup luksRemoveKey /dev/sdc
$ cryptsetup luksRemoveKey /dev/sdc /etc/secreto_a_eliminar

## O si no tenemos/recordamos la contraseña, especificar
## el slot que queremos eliminar (nos pedirá alguna de las
## contraseñas (o ficheros contraseña con --key-file)
## restantes en otro slot
$ cryptsetup luksKillSlot /dev/sdc 2
$ cryptsetup --key-file /etc/secreto_valido /dev/sdc 2

Copia de seguridad

El punto más débil de nuestro dispositivo cifrado es la cabecera LUKS. Sin ésta sería imposible acceder a los datos que contiene. Es recomendable por tanto, realizar una copia de seguridad de ella que nos permita acceder a los datos cifrados en el caso de que la cabecera LUKS quede dañada (por error en su gestión, o daño físico en el dispositivo de almacenamiento).

## Podemos sacar una copia de la cabecera con el siguiente comando
$ cryptsetup luksHeaderBackup /dev/sdc --header-backup-file cabecera_backup
## O restaurar una cabecera dañada desde un backup
$ cryptsetup luksHeaderRestore /dev/sdc --header-backup-file cabecera_backup

No metas cosas en criptas, cogen humedad

Cada vez que alguien dice «encriptar» o «encriptado» Dios mata un gatito. FYI.

$ exit