Saltar la navegación

Cifrado de una partición en Debian

Para cifrar particiones, volúmenes lógicos (LVs) o ficheros loop, podemos usar el programa cryptsetup (paquete cryptsetup) basado en la especificación de cifrado de disco LUKS

Cryptsetup

LUKS (de sus siglas en inglés, Linux Unified Key Setup) es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinada a sistemas GNU/Linux. Mientras que la mayoría del software de cifrado de discos se basan en diferentes formatos no documentados e incompatibles entre sí, LUKS especifica un formato estándar en disco, independiente de la plataforma, para usar con diversas herramientas. Esto facilita la compatibilidad y la interoperabilidad entre los diferentes programas.

Un disco o partición cifrada basada en LUKS, puede utilizarse también en Windows utilizando el software de código abierto FreeOTFE. Por lo tanto, podríamos trabajar, por ejemplo, con un lápiz USB cifrado con LUKS, tanto en GNU/Linux como en Windows, simplemente tendríamos que utilizar un sistema de ficheros entendible por los dos sistemas operativos, por ejemplo FAT32 o NTFS, pero no ext4, pues Windows no lo entendería.

Debido a la falta de funcionalidad de Windows, sólo puede ser utilizada la primera partición de la unidad. Así que, si queremos cifrar una partición y que esta sea portable entre los dos sistemas operativos, tendremos que formatear la unidad USB con una sola partición.

Los gestores de archivos actuales, soportan el reconocimiento automático de particiones LUKS. Estos gestores solicitarán la contraseña del dispositivo cifrado cuando este se conecte y montará la partición como una unidad extraíble. Esta integración es muy útil para el trabajo diario pero implica que no se puede usar un fichero-llave (fichero cuyo contenido es la clave), sólo será posible introducir la contraseña manualmente.

La instalación de cryptsetup en GNU/Linux es como sigue:

# aptitude update
# aptitude upgrade
# aptitude install cryptsetup

El módulo del kernel que se necesita que esté cargado en memoria es el dm_crypt, que podemos comprobar si está en memoria con:

# lsmod | grep dm_crypt

y si no lo estuviera, lo cargamos con la siguiente instrucción, aunque la ejecución de cryptsetup lo carga automáticamente:

# modprobe dm_crypt

Vamos a suponer que disponemos de un segundo disco SATA con una partición (/dev/sdb1), la cual la queremos utilizar para guardar información cifrada, podría servir para guardar todo el contenido del directorio /home, pero en los ejemplos simplemente la montaremos en un directorio de /media para ver que funciona.

La sintaxis general del uso del comando cryptsetup es la siguiente:

# cryptsetup [opción...] acción argumento_acción...

Antes de utilizar una partición podemos asegurarnos de destruir toda la información que contenga, para lo cual nos pueden servir alguno de los siguientes dispositivos: /dev/zero, /dev/random o /dev/urandom. Usándolos con la orden dd podemos sobrescribir todo el contendido de la partición /dev/sdb1. Esto será más seguro que la destrucción que hace el propio programa cryptsetup. Una forma sería la siguiente:

# dd if=/dev/urandom of=/dev/sdb1
dd: escribiendo en «/dev/sdb1»: No queda espacio en el dispositivo
202753+0 registros leídos
202752+0 registros escritos
103809024 bytes (104 MB) copiados, 126,905 s, 818 kB/s

El primer paso que hay que realizar es formatear la partición para convertirla en una partición LUKS y así cryptsetup podrá trabajar con ella. Para ello usaremos la acción luksFormat:

# cryptsetup luksFormat /dev/sdb1 

WARNING!
========
Esto sobreescribirá los datos en /dev/sdb1 de forma irrevocable.

Are you sure? (Type uppercase yes): YES
Introduzca la frase contraseña:
Verifique la frase contraseña:

En este paso, hemos respondido YES (en mayúsculas) a la pregunta de si estamos seguros de destruir todos los datos de la partición. Además, hemos introducido por dos veces la contraseña de acceso al dispositivo LUKS.

Cuando damos formato LUKS a un dispositivo hablamos de dos términos similares, pero diferentes:

  • Contraseña. Es la que nos permite acceder al dispositivo LUKS, y puede ser tecleada (lo hecho en el paso anterior) o contenida en un fichero (fichero clave). Esta contraseña no es usada para cifrar los datos. Una de las ventajas de usar LUKS es que podemos usar varias contraseñas o ficheros contraseña para un mismo dispositivo.
  • 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 de 256 bits por defecto.

El formato LUKS se caracteriza por crear una cabecera al inicio de la partición que incluye la información del algoritmo de cifrado, tamaño de la clave, contraseñas en uso, etc. Podemos consultar dicha cabecera con la acción luksDump:

# cryptsetup luksDump /dev/sdb1
LUKS header information for /dev/sdb1

Version:           1
Cipher name:       aes
Cipher mode:       xts-plain64
Hash spec:         sha1
Payload offset:    4096
MK bits:           256
MK digest:         0e a9 4b c2 94 64 dc 7a 05 ae 5e 9d 15 9f fb db 80 69 5b 89
MK salt:           32 e6 56 2e 5d 7b ea e7 5b ae ee 9b ae 68 b4 20
                   3f a9 5a 55 89 00 7f 41 46 e3 9f a6 f1 ca 53 39
MK iterations:     97500
UUID:              e60c8166-fa2f-4cf7-89b9-2fea02cc6860

Key Slot 0: ENABLED
    Iterations:             453900
    Salt:                   61 2f 31 d0 b5 56 00 6d 28 55 c7 31 82 e2 cd 4b
                              4f d3 c0 23 89 ed ac 94 0a 66 ec 55 4e 57 e3 80
    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 la información de salida anterior podemos ver que la partición LUKS está usando AES como algoritmo de cifrado, que el tamaño de la clave es de 256 bits, que la función hash es SHA1 y que hay una contraseña de las 8 posibles (Key Slot 0: ENABLED).

Los valores por defecto que usa cryptsetup los podemos ver en las últimas líneas de la ayuda dada con --help:

# cryptsetup --help | tail -n 8
Parámetros predefinidos de fábrica de clave y de frase contraseña:
    Tamaño máximo del fichero de claves: 8192k8, Longitud máxima de frase contraseña interactiva: 512 (caracteres)
Tiempo PBKDF2 de iteración de LUKS predefinido: 1000 (ms)

Parámetros predefinidos de fábrica del algoritmo de cifrado de dispositivos:
    bucle-AES: aes, Clave 256 bits
    sin cifrado: aes-cbc-essiv:sha256, Clave: 256 bits, Contraseña «hashing»: ripemd160
    LUKS1: aes-xts-plain64, Clave: 256 bits, «hashing» de la cabecera LUKS: sha1, Generador de números aleatorios: /dev/urandom

Donde podemos ver que el tamaño máximo de un fichero clave (8192 KB), la longitud máxima de una contraseña tecleada (512 caracteres), el algoritmo de cifrado (aes-xts-plain64), la longitud de la contraseña de cifrado (256 bits), el algoritmo hash utilizado (sha1), los números aleatorios los coge de /dev/urandom, etc.

Los valores por defecto pueden cambiarse utilizando las opciones de cryptsetup, por ejemplo:

--hash nombre_algoritmo_hash

-h nombre_algoritmo_hash

Cambia el algoritmo hash.

--cipher nombre_algoritmo_cifrado

-c nombre_algoritmo_cifrado

Cambia el algoritmo de cifrado.

--key-size numero_bytes

-s numero_bytes

Cambia la longitud de la clave de cifrado. Siempre tiene que ser un múltiplo de 8.  

Por ejemplo, el siguiente comando cambia el algoritmo hash y la longitud de la clave de cifrado, en el momento de la creación del dispositivo LUKS:

# cryptsetup --hash=sha256 --key-size=512 luksFormat /dev/sdb1

Se puede también usar una contraseña de acceso al dispositivo LUKS escrita en un fichero (mucho cuidado con ese fichero, contiene la clave), en vez de teclearla. Para ello, hay que pasar dicho fichero clave como argumento de la acción luksFormat. Por ejemplo, en primer lugar creamos el fichero /root/clave (1 MByte) usando números aleatorios:

# dd if=/dev/urandom of=/root/clave bs=1M count=1
1+0 registros leídos
1+0 registros escritos
1048576 bytes (1,0 MB) copiados, 0,138253 s, 7,6 MB/s

y a continuación creamos el dispositivo LUKS con la contraseña de acceso que está en el fichero anterior:

# cryptsetup luksFormat /dev/sdb1 /root/clave

WARNING!
========
Esto sobreescribirá los datos en /dev/sdb1 de forma irrevocable.

Are you sure? (Type uppercase yes): YES

Una vez que hemos creado el dispositivo LUKS, antes de poderlo usar como un dispositivo normal debemos abrirlo con cryptsetup, para que este lo controle a partir de ahora y hasta que se cierre. Esta operación se hace con la acción open (luksOpen es la sintaxis antigua):

# cryptsetup open /dev/sdb1 disco_seguro
Introduzca la frase contraseña de /dev/sdb1:

Si en vez de usar una contraseña tecleada, usamos un fichero-clave, debemos indicarlo con la opción --key-file:

# cryptsetup --key-file=/directorio/fichero_clave open /dev/sdb1 disco_seguro

El último argumento de la acción open del comando anterior, disco_seguro, es el nombre del dispositivo LUKS descifrado, y es el que utilizaremos a partir de ahora para trabajar con /dev/sdb1, pues este último nombre de dispositivo solo estará disponible para cryptsetup. El nombre completo del nuevo dispositivo es /dev/mapper/disco_seguro, y técnicamente se dice que este mapea a /dev/sdb1.

# ls -l /dev/mapper/disco_seguro 
lrwxrwxrwx 1 root root 7 nov 22 18:50 /dev/mapper/disco_seguro -> ../dm-0

Vemos que /dev/mapper/disco_seguro es un enlace simbólico a /dev/dm-0, y podríamos usar este último dispositivo, pero es más conveniente utilizar el nombre más legible que hemos puesto y que recordaremos mejor, aunque la ruta sea un poco más larga.

Como el dispositivo se acaba de crear, tras abrirlo por primera vez, lo que debemos hacer es formatearlo, por ejemplo:

# mkfs.ext4 /dev/mapper/disco_seguro 
mke2fs 1.42.12 (29-Aug-2014)
Se está creando El sistema de ficheros con 99328 1k bloques y 24856 nodos-i

UUID del sistema de ficheros: 64cfaa74-73a9-48e7-90c7-22544afccc89
Respaldo del superbloque guardado en los bloques:
    8193, 24577, 40961, 57345, 73729

Reservando las tablas de grupo: hecho                           
Escribiendo las tablas de nodos-i: hecho                           
Creando el fichero de transacciones (4096 bloques): hecho
Escribiendo superbloques y la información contable del sistema de ficheros: hecho

Hay que hacer hincapié en el nombre del dispositivo que se ha formateado, el dispositivo LUKS descifrado /dev/mapper/disco_seguro, el cual mapea al dispositivo físico /dev/sdb1.

A partir de ahora ya solo nos queda montarlo y podremos empezar a usarlo:

# mount /dev/mapper/disco_seguro /media/disco_seguro

Con la acción status podemos consultar el estado del dispositivo LUKS:

# cryptsetup open /dev/sdb1 disco_seguro
# cryptsetup status disco_seguro
/dev/mapper/disco_seguro is active.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  device:  /dev/sdb1
  offset:  4096 sectors
  size:    198656 sectors
  mode:    read/write
# mount /dev/mapper/disco_seguro /media/disco_seguro
# cryptsetup status disco_seguro
/dev/mapper/disco_seguro is active and is in use.
  type:    LUKS1
  cipher:  aes-xts-plain64
  keysize: 256 bits
  device:  /dev/sdb1
  offset:  4096 sectors
  size:    198656 sectors
  mode:    read/write

Cuando hayamos terminado de trabajar con el dispositivo LUKS, únicamente nos quedaría desmontarlo normalmente:

# umount /media/disco_seguro

y cerrarlo con la acción close (luksClose es la sintaxis antigua) para que se quede cifrado:

# cryptsetup close disco_seguro
# cryptsetup status disco_seguro
/dev/mapper/disco_seguro is inactive.

Como vimos anteriormente, un dispositivo LUKS puede contener hasta 8 contraseñas distintas, esto permite que varios usuarios puedan acceder al mismo dispositivo cada uno con su contraseña, y si posteriormente hay que restringirle el acceso a uno de ellos, simplemente borraremos su contraseña. También, tener varias contraseñas permite automatizar tareas, como por ejemplo las copias de seguridad (backups), las cuales pueden realizarse utilizando un fichero de contraseña, lo que haría posible no estar presente durante el backup, pero a la vez, podemos tener para otros usos una segunda contraseña que se pueda teclear, podría ser para el caso de pérdida del fichero de contraseña por rotura o robo del disco donde está almacenado.

Para añadir una segunda contraseña tecleada al dispositivo de nuestro ejemplo (/dev/sdb1) ejecutaríamos cryptsetup con la acción luksAddKey tal como sigue:

# cryptsetup luksAddKey /dev/sdb1
Introduzca cualquier frase contraseña que exista:
Introduzca una nueva frase contraseña para la ranura de claves:
Verifique la frase contraseña:

Comprobamos que hay dos contraseñas mirando la cabecera del dispositivo LUKS:

# cryptsetup luksDump /dev/sdb1
LUKS header information for /dev/sdb1

Version:           1
Cipher name:       aes
Cipher mode:       xts-plain64
Hash spec:         sha1
Payload offset:    4096
MK bits:           256
MK digest:         41 0f eb e0 9e 59 32 04 0e be ee 4d 88 88 3a 73 fd 21 dc e5
MK salt:           bd 3d 75 43 19 50 1a e4 8e 35 ae da f2 7b ae 97
                   77 f3 64 12 4d e5 e6 5d e7 7e 71 6c e0 f7 29 a8
MK iterations:     108000
UUID:              1df671db-9aa1-496b-91c2-af099a5e602e

Key Slot 0: ENABLED
    Iterations:             395061
    Salt:                   30 0d 03 88 56 08 a2 91 ac fb 15 2f 44 f4 8e e3
                              aa ec 90 a1 98 c9 e6 3a e9 56 0a ce 4a 79 6f f3
    Key material offset:    8
    AF stripes:                4000
Key Slot 1: ENABLED
    Iterations:             392637
    Salt:                   98 03 91 2f e3 77 e6 bd 85 92 5a e4 8b 99 c0 9c
                              75 37 5c 4b bc d6 9e 4f f3 c5 cc 8f 06 30 3c 92
    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

Y efectivamente, hay dos slots (0 y 1) ocupados.

Otras posibilidades serían:

  • Añadir una contraseña tecleada accediendo al dispositivo con un fichero de contraseña (opción --key-file):
# cryptsetup --key-file=/directorio/fichero_contraseña luksAddKey /dev/sdb1
  • Añadir una contraseña de fichero con una contraseña de acceso tecleada:
# cryptsetup luksAddKey /dev/sdb1 /directorio/fichero_contraseña_nuevo
  • Añadir una contraseña de fichero con una contraseña de fichero para el acceso:
# cryptsetup --key-file=/directorio/fichero_contraseña luksAddKey /dev/sdb1 /directorio/fichero_contraseña_nuevo

Para eliminar una contraseña se usa la acción luksRemoveKey, y según sea la contraseña, tecleada o de fichero, ejecutaríamos respectivamente uno de los dos siguientes comandos:

# cryptsetup luksRemoveKey /dev/sdb1
Introduzca la frase contraseña que hay que borrar:
# cryptsetup luksRemoveKey /dev/sdb1 /directorio/fichero_contraseña_a_borrar

También, con la acción luksKillSlot, es posible borrar una contraseña especificando el slot, en este caso, tendremos que utilizar para acceder al dispositivo una de las contraseñas restantes (tecleada o fichero). Por ejemplo, borrar el slot 3 podría hacerse de alguna de los dos maneras siguientes:

# cryptsetup luksKillSlot /dev/sdb1 3
Introduzca cualquier frase contraseña que quede:
# cryptsetup --key-file=/directorio/fichero_contraseña luksKillSlot /dev/sdb1 3

El punto más débil de un dispositivo LUKS es su cabecera. Sin esta 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).

El backup de la cabecera de un dispositivo LUKS se hace con la acción luksHeaderBackup:

# cryptsetup luksHeaderBackup /dev/sdb1 --header-backup-file /directorio/cabecera_backup

Para restaurarla está la acción:

# cryptsetup luksHeaderRestore /dev/sdb1 --header-backup-file /directorio/cabecera_backup

También, un aspecto importante es el montaje automático de una partición LUKS cuando arranca el sistema, para ello debemos trabajar con los ficheros /etc/crypttab y /etc/fstab.

El fichero /etc/crypttab lo utiliza cryptsetup en el arranque para realizar el mapeo de los dispositivos físicos que se especifiquen. Cada línea representa a un dispositivo y las cuatro columnas que lo describen significan lo siguiente:

  • Nombre del dispositivo que mapeará al dispositivo físico.
  • Nombre del dispositivo físico.
  • Fichero de contraseña o bien none para indicar que la contraseña se tecleará.
  • Opciones para cryptsetup, normalmente se especificará: luks.

Para nuestro ejemplo:

# <target name> <source device> <key file> <options> 
disco_seguro /dev/sdb1 none luks

En el fichero /etc/fstab hacemos referencia al dispositivo /dev/mapper/disco_seguro:

# <file system>            <mount point>           <type>  <options>       <dump>  <pass>
/dev/mapper/disco_seguro   /media/disco-seguro     ext4    defaults        0       0

Con lo anterior, al arrancar el sistema, se nos pedirá la contraseña de acceso al dispositivo LUKS.

Si quisiéramos utilizar en /etc/fstab el UUID del dispositivo LUKS en vez del nombre del mapeador, podríamos consultar el UUID con la acción luksUUID:

# cryptsetup luksUUID /dev/sdb1
6eb6ce62-188a-4b97-b0bb-5a5b1b2d7ef8

y entonces en /etc/fstab:

# <file system>                             <mount point>           <type>  <options>       <dump>  <pass>
UUID=6eb6ce62-188a-4b97-b0bb-5a5b1b2d7ef8   /media/disco-seguro     ext4    defaults        0       0