Cifrado de datos en discos duros externos

Primeros pasos

De nuevo voy a cifrar los contenidos de un disco duro USB en el que voy a ir guardando los directorios de trabajo de los proyectos pasados en los que participé, que ya comienza a pesar demasiado como para llevarlo siempre en el disco duro del portátil. Por otro lado, los discos duros sólidos tienen menos capacidad que los de cabezas, por lo que quiero necesitar menos espacio.

Una opción es utilizar dispositivos loop pero dm-crypt sigue pareciendo la mejor solución para cifrar particiones e incluso poder meter el sistema raíz cifrado. Seguimos este HOWTO.

root@reborn:/home/acs# apt-get install cryptsetup hashalot
root@reborn:/home/acs# modprobe dm_crypt
root@reborn:/home/acs# modprobe dm_mod
root@reborn:/home/acs# modprobe aes
root@reborn:/home/acs# cat /proc/crypto
name         : aes
....
type         : cipher
blocksize    : 16
min keysize  : 16
max keysize  : 32

name         : md5
....
type         : digest
blocksize    : 64
digestsize   : 16
root@reborn:/home/acs# umount /dev/sdb1
root@reborn:/home/acs# cryptsetup -y create granero /dev/sdb1 
Enter passphrase: 
Verify passphrase:
root@reborn:/home/acs# dmsetup ls
granero (254, 0)

You now have a "virtual" block device called /dev/mapper/granero, which is mapped (through the crypt target) to /dev/sdb1.

root@reborn:/home/acs# mkfs -t ext3 /dev/mapper/granero

Automatizando el montaje

Es básico que sea sencillo de manejar el disco duro cifrado ya que dentro de unos meses no me acordaré de todo esto y no quiero tener que estas viniendo a leer esto cada vez que quiera utilizar el disco. Por ello he añadido a "fstab":

acs@reborn:~$ tail -3 /etc/fstab
# crypto USB
/dev/mapper/granerob /media/granerob     ext3    defaults,noauto,user        0       0
/dev/mapper/graneroc /media/graneroc     ext3    defaults,noauto,user        0       0

y basta con que enchufe el disco duro y reinicie el sistema:

/etc/init.d/cryptdisks restart

que utiliza la configuración en:

acs@reborn:~$ cat /etc/crypttab 
# <target name> <source device>         <key file>      <options>
granerob /dev/sdb1 none cipher=aes
graneroc /dev/sdc1 none cipher=aes

y luego solo hay que montar "/media/granerob" o "/media/graneroc" en función de como se haya detectado el disco usb ... ¿un poco cochino no? Vamos a buscar algo más elegante gracias a HAL.

Mucho ojo al meter la clave que si te equivocas en "/etc/init.d/cryptdisks restart" no dice nada pero luego no puedes acceder a los contenidos del disco.

Trabajando con HAL

HAL es la "Hardware Abstraction Layer" y es usada por el demonio "hald" para ir informando al sistema de los eventos de hardware que se van produciendo, entre ellos el de que un nuevo disco USB ha sido introducido. Si capturamos este evento cuando se pincha el disco USB podríamos hacer todo el proceso transparente de configuración y acceso al disco.

Los discos duros tienen un identificador de serie único. Lo podemos ver con HAL una vez enchufado el disco USB con:

acs@reborn:~$ hal-device > /tmp/info
acs@reborn:~$ cat /tmp/info
....
1: udi = '/org/freedesktop/Hal/devices/storage_serial_Ext_Hard_Disk_S07I2501A00000308845_0_0'
....
  storage.serial = 'Ext_Hard_Disk_S07I2501A00000308845-0:0'  (string)
...

HAL tiene mucha información, por ejemplo como localizar el disco en el sistema "block.device = '/dev/sdc'". Por ejemplo si queremos saber como montar el disco basta con:

acs@reborn:~$ hal-device /org/freedesktop/Hal/devices/storage_serial_Ext_Hard_Disk_S07I2501A00000308845_0_0 | grep block.device | cut -d\' -f2
/dev/sdc

y de forma más elegante

acs@reborn:tmp$ hal-get-property --udi /org/freedesktop/Hal/devices/storage_serial_Ext_Hard_Disk_S07I2501A00000308845_0_0 --key block.device
/dev/sdc

y esto funcionará independientemente de que se identifique el disco a veces como "sdb" y a veces como "sdc" o "sdd" o lo que sea. Pero, ¿cómo sabemos cuando el disco se ha enchufado? El núcleo avisa con un evento a "udevd" de que hay un nuevo dispositivo disponible y udevd ejecuta las reglas asociadas a ese dispositivo. Para saber como "udev" identifica un dispositivo:

acs@reborn:~$ hal-device /org/freedesktop/Hal/devices/storage_serial_Ext_Hard_Disk_S07I2501A00000308845_0_0 | grep sysfs
  linux.sysfs_path = '/sys/block/sdc'  (string)
acs@reborn:~$ udevinfo --query=all --path=/sys/block/sdc
P: /block/sdc
N: sdc
S: disk/by-id/usb-Ext_Hard_Disk_S07I2501A00000308845-0:0
S: disk/by-path/pci-0000:00:1d.7-usb-0:2:1.0-scsi-0:0:0:0
E: DEVTYPE=disk
E: ID_VENDOR=Ext_Hard
E: ID_MODEL=Disk
E: ID_REVISION=0000
E: ID_SERIAL=Ext_Hard_Disk_S07I2501A00000308845-0:0
E: ID_SERIAL_SHORT=S07I2501A00000308845
E: ID_TYPE=disk
E: ID_INSTANCE=0:0
E: ID_BUS=usb
E: ID_PATH=pci-0000:00:1d.7-usb-0:2:1.0-scsi-0:0:0:0

Esta información no es útil para saber como crear el script que se ejecute sólo cuando se pinche este disco. Las reglas que ejecuta udevd se encuentran en:

acs@reborn:~$ tree /etc/udev/rules.d/
/etc/udev/rules.d/
|-- 00-init.rules
...
|-- README
`-- libmtp.rules -> ../libmtp.rules

Por ejemplo para informar a HAL de las cosas que pasan:

acs@reborn:~$ cat /etc/udev/rules.d/95-hal.rules 
# Have udev pass data over a socket to hal 
RUN+="socket:/org/freedesktop/hal/udev_event"

Tras reflexionar un poco, lo ideal sería que gnome-volume-manager que escucha siempre el bus DBUS de sesión por si hay nuevos dispositivos, se encargara de gestionar el montar dispositivos cifrados. Pero es algo muy específico y que aún no está soportado, y "gnome-volume-manager" no parece sencillo de extender con plugins. Y el tener un programa siempre funcionando aparte para montar dispositivos cifrados tampoco parece el sistema más adecuado. Lo ideal sería que "gnome-volume-manager" permitiera que se ejecutaran programas ante la aparición de nuevos dispositivos, algo que hace pero no para volúmenes de datos. Todo apunta a tendremos que trabajar a nivel de udev y crear un nuevo programa a ejecutar.

Configurando udev para la automatización total

Cuando se pincha un dispositivo se ejecutan los programas indicando la acción "add". Basta con poner este programa en el directorio "/etc/udev/rules.d/" para que se ejecute siempre que haya un evento de hardware comunicado por el núcleo. Son programas macro cuya ejecución debe de ser muy rápida. Estoy terminando de retocar un script que tendrá una pinta como:

# For automounting a crypted device

ACTION!="add", RUN+="/bin/sh -c 'echo NO ES ADD>> /tmp/CRYPTED', "GOTO="persistent_storage_end"
SUBSYSTEM!="block", GOTO="persistent_storage_end"
ENV{DEVTYPE} != "partition", RUN+="/bin/sh -c 'echo NO ES partition>> /tmp/CRYPTED', GOTO="persistent_storage_end"
# Montar aquí la partición ... habrá que dejar la clave en algún fichero protegido

LABEL="persistent_storage_end"

CifradoDatos (last edited 2009-04-20 09:52:53 by localhost)