Драйвер loop-AES представляет собой, как нетрудно догадаться, модификацию стандартного Linux-драйвера loop.ko. Того самого, который используется для так называемого кольцевого подключения различных сущностей в качестве виртуальных блочных устройств (например, ISO-образов). В отличие от оригинала, создающего тонкую прослойку между чем-либо и виртуальным устройством, loop-AES еще и производит модификацию пропускаемых через него данных, шифруя записываемую или читаемую из устройства информацию.
Это делает его универсальной системой шифрования любой информации, будь то файлы (подключенные с помощью «mount -o loop»), дисковые разделы, RAID-тома, своп-области, флеш-брелки и т.п. Шифруя раздел с помощью этого драйвера, пользователь получает что-то вроде переходника в виде loop-устройства, без которого получить доступ к данным будет невозможно.
Подготовленный читатель может сказать, что loop-AES просто «не нужен», потому как ванильное ядро уже давно включает в себя драйвер, способный шифровать любые данные (тот самый dm-crypt), да еще и поддерживающий свыше десятка различных алгоритмов. И будет не прав. Конек loop-AES – в непревзойденной скорости работы, многоуровневой системе безопасности и интеграции со стандартными утилитами GNU/Linux (gpg, mount). Jari Ruusu, автор loop-AES, неоднократно указывал на недостатки других систем шифрования, доступных в Linux, благодаря чему, были исправлены серьезные проблемы безопасности TrueCrypt и dm-crypt. Даже сегодня, когда многие из проблем dm-crypt, на которые, не смущаясь, показывали пальцем эксперты по безопасности, уже решены, loop-AES так и продолжает занимать место наиболее безопасного и производительного решения.
Основная причина, по которой loop-AES часто забывают упомянуть и боятся с ним связываться, заключается в нетривиальном способе установки, включающем в себя необходимость перекомпиляции ядра и модификации ряда системных утилит. Во многом это объясняется отсутствием внятных пошаговых руководств как в рунете, так и в западных источниках. Я постораюсь восполнить этот информационный пробел и раскрою тонкости установки и использования этого драйвера.
Подготовка к установке
Пакет loop-AES состоит из четырех компонентов: модифицированного драйвера loop.ko, набора патчей для системных утилит, патча для ядра Linux и коллекции модулей, обеспечивающих поддержку алгоритмов шифрования Blowfish, Serpent и Twofish. Первые два компонента нам понадобятся в любом случае, а вот третий и четвертый совсем не обязательны. Во-первых, драйвер можно собрать и отдельно от ядра, а во-вторых, используемый по умолчанию алгоритм AES - один из лучших. Менять его на какой-то другой не имеет смысла.
В качестве подопытной системы я буду использовать дистрибутив Ubuntu 11.04, построенный на ядре 2.6.38, но читатель может использовать любой другой дистрибутив и ядро.
Для начала получим исходники ядра Linux (от 2.0 до 2.6.39, драйвер работает с любым из них). Для Ubuntu выполняем приведенную ниже последовательность действий; для других дистрибутивов - устанавливаем необходимый для сборки ядра комплект пакетов, переходим в каталог /usr/src и с помощью wget получаем ядро с kernel.org.
# apt-get install linux-source
# apt-get install build-essential ncurses-dev fakeroot
# apt-get install kernel-package
Распакуем исходники, скопируем конфигурационный файл текущего ядра (он может называться и по-другому) и запустим конфигуратор:
# cd /usr/src
# tar -xjf linux-source-2.6.38.tar.bz2
# cp /boot/config-2.6.38-generic ./linux-source-2.6.38/.config
# cd ./linux-source-2.6.38
# make menuconfig
Единственное, что мы должны сделать - убрать из ядра поддержку драйвера loop, чтобы он не конфликтовал с loop-AES: Device Drivers → Block devices → Loopback device support → n (или CONFIG_BLK_DEV_LOOP=n в конфигурационном файле). Также добавим метку к новому ядру, чтобы дать установщику loop-AES понять, что в текущем ядре он нам не нужен, а нужен в новом: General Setup → Local version → "-noloop" (CONFIG_LOCALVERSION=-noloop).
Если читатель намерен использовать loop-AES для шифрования корневого раздела, то он должен убедиться, что опция General Setup → Initial RAM filesystem and RAM disk (initramfs/initrd) support (CONFIG_BLK_DEV_INITRD) включена, и вкомпилировать необходимые IDE/SATA драйвера и поддержку файловой системы корневого раздела в ядро (не модулями!).
Собираем и устанавливаем ядро (рецепт для Ubuntu):
# make-kpkg clean
# make-kpkg -initrd kernel_image kernel_headers
# cd ..
# dpkg -i linux-image-2.6.38-noloop*
Рецепт для всех остальных дистрибутивов:
# make
# make modules_install
# cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.38-noloop
Редактируем /boot/grub/grub.conf, чтобы показать загрузчику новое ядро (для Ubuntu не требуется), и отправляем машину перезагрузку.
Установка
Загрузившись с новым ядром, приступаем к установке драйвера loop-AES:
# sudo su
# cd /usr/src
# wget http://loop-aes.sourceforge.net/loop-AES-latest.tar.bz2
# tar -xjf loop-AES-latest.tar.bz2
# cd loop-AES-v3.6c
# make clean
# make LINUX_SOURCE=/usr/src/linux-source-2.6.38
Подчищаем исходники ядра:
# cd /usr/src/linux-source-2.6.38
# make clean
И переходим к сборке и установке модифицированных утилит (mount, umount, losetup, swapon и swapoff). Все они распространяются в пакете util-linux, но в стандартном виде не подходят для управления шифрованными дисковыми разделами и swap-областями. Поэтому их придется пропатчить:
# cd /usr/src
# wget http://www.kernel.org/pub/linux/utils/util-linux/v2.19/util-linux-2.19.tar.bz2
# tar -xjf util-linux-2.19.tar.bz2
# cd util-linux-2.19
# patch -p1 </usr/src/loop-AES-v3.6c/util-linux-2.19.diff
# CFLAGS="-O2 -Wall" ./configure
# make SUBDIRS=mount
После того, как утилиты будут собраны, установим их в систему (весь пакет устанавливать опасно, поэтому мы вручную скопируем только необходимые утилиты):
# cd mount
# install -m 4755 -o root mount umount /bin
# install -m 755 losetup swapon /sbin
# rm -f /sbin/swapoff
# ln -s /sbin/swapon /sbin/swapoff
Наконец, протестируем loop-AES на работоспособность:
# cd /usr/src/loop-AES-v3.6c
# make tests
Если в самом конце на экране появится сообщение Test results ok, значит, теперь у нас есть готовый к работе loop-AES. Иначе все шаги установки придется повторить.
Сценарий 1. Шифрование swap-раздела
Шифрование swap-раздела - процедура необязательная, но чрезвычайно важная. Дело в том, что данные утилиты gpg, используемой loop-AES для хранения и защиты ключей шифрования, не застрахованы от попадания в область подкачки. Это может привести к тому, что при определенных обстоятельствах, человек, укравший ноутбук, сможет пропарсить swap на наличие ключей, найти их и прочитать зашифрованный раздел с важными данными. Чтобы избежать такого позора, достаточно просто настроить шифрование swap-раздела с помощью одноразовых ключей. Для этого отключаем swap (swapoff -a) и добавляем в /etc/fstab примерно такую запись:
/dev/hda1 none swap sw,loop=/dev/loop1,encryption=AES128 0 0
После этого забиваем swap-раздел нулями и инициализируем его:
# dd if=/dev/zero of=/dev/hda1 bs=64k conv=notrunc
# mkswap /dev/hda1
Все, подключаем зашифрованный swap (будет шифроваться с помощью случайных ключей при каждом подключении):
# swapon -a
Кроме того, удаляем каталог /var/log/ksymoops, чтобы modprobe, загружающий модуль loop.ko, не ругался на невозможность записи в файловую систему, которая монтируется в режиме чтения/записи уже после подключения swap:
# rm -rf /var/log/ksymoops
Сценарий 2. Шифрование раздела с использованием 65 случайных ключей
Этот сценарий описывает использование loop-AES для шифрования одного из разделов жесткого диска (/dev/sda2, точка монтирования /mnt) с использованием сгенерированных случайным образом 65 ключей (один блок данных - один ключ, по порядку). Они будут зашифрованы с помощью gpg и помещены на съемный носитель (USB-брелок, примонтированный к /media/usbstick).
Создадим 65 случайных ключей и зашифруем их с помощью gpg:
$ head -c 3705 /dev/random | uuencode -m - | head -n 66 | tail -n 65 |\
gpg --symmetric -a >/media/usbstick/keyfile.gpg
Вводим пароль для доступа к файлу ключей.
Заполним раздел случайными данными. Для этого создадим псевдо-устройство /dev/loop2 поверх /dev/sda2, указав, что мы используем алгоритм AES128 и файл ключей /media/usbstick/keyfile.gpg:
# echo -n "ПаРоЛь" | losetup -p 0 -e AES128 -K /media/usbstick/keyfile.gpg /dev/loop2 /dev/sda2
Запишем в псевдо-устройство случайную информацию:
# dd if=/dev/zero of=/dev/loop2 bs=4k conv=notrunc 2>/dev/null
Отключим псевдо-устройство:
# losetup -d /dev/loop2
Добавим в /etc/fstab следующую запись:
/dev/sda2 /mnt ext3 defaults,noauto,loop=/dev/loop2,encryption=AES128,gpgkey=/media/usbstick/keyfile.gpg 0 0
Теперь на устройстве можно создать файловую систему:
# losetup -F /dev/loop2
# mkfs -t ext3 /dev/loop2
# losetup -d /dev/loop2
С помощью флага -F мы заставили losetup взять всю необходимую ей информацию из файла /etc/fstab, затем создали на псевдо-устройстве файловую систему ext3 и удалили его.
Наконец, примонтируем файловую систему:
# mount /mnt
После этого в выводе команды «losetup -a» ты должен увидеть информацию о псевдо-устройстве /dev/loop2, которое подключено к /dev/hda2. Проверку файловой системы необходимо производить применительно к loop-устройству:
# losetup -F /dev/loop2
# fsck -t ext3 -f -y /dev/loop2
# losetup -d /dev/loop2
Сценарий 3. Шифрование /tmp
Третий сценарий демонстрирует одну из интереснейших функций loop-AES: автоматическое генерирование ключей с последующим созданием новой файловой системы на loop-устройстве. Нужно это для разделов, хранящих временные данные. Нет смысла создавать перманентные ключи и запоминать пароль для доступа к разделу, содержащему каталог /tmp, который при следующей перезагрузке будет очищен.
Чтобы зашифровать каталог /tmp (или любой другой) таким способом, просто размонтируй его (umount /tmp), следует добавить в /etc/fstab следующую строку:
/dev/sda3 /tmp ext2 defaults,loop=/dev/loop3,encryption=AES128,phash=random/1777 0 0
и смонтировать каталог снова:
# mount /tmp
Команда mount не спросит пароля, а просто подключит /dev/loop3 к устройству /dev/sda3, создаст новую файловую систему, сгенерирует 65 случайных ключей и воспользуется ими для шифрования записываемых данных. Права на каталог /tmp будут выставлены в значение 1777 (опция «phash=random/1777»).
Обратите внимание, что выбор файловой системы ext2 в этом случае не требование, а просто здравый смысл. Зачем использовать журналируемую файловую систему в ситуации, когда ФС заново создается при каждом монтировании?
Сценарий 4. Шифрование корневого раздела
Четвертый и заключительный сценарий использования loop-AES описывает процесс настройки системы для шифрования корневого раздела. Сразу оговорюсь, что это непростая процедура, которая потребует создания каталога /boot на отдельном разделе и наличия под рукой LiveCD или отдельно стоящего дистрибутива Linux. В основе метода лежит использование небольшого образа initrd, который еще до загрузки запустит утилиты insmod и losetup, располагающиеся в каталоге /boot, для подключения шифрующего loop-устройства поверх корневого раздела еще до фактической загрузки системы.
Первое, что необходимо сделать, – это скачать и установить dietlibc, минималистичную библиотеку языка Си, код которой будет использован в образе initrd:
# cd /usr/src
# wget ftp://ftp.kernel.org/pub/linux/libs/dietlibc/dietlibc-0.32.tar.bz2
# tar -xjf dietlibc-0.32.tar.bz2
# cd dietlibc-0.32
# make
# install bin-i386/diet /usr/local/bin
Также нам понадобится утилита aespipe, с помощью которой мы зашифруем существующие на корневом разделе данные, не потеряв их:
# cd /usr/src
# wget http://loop-aes.sourceforge.net/aespipe-latest.tar.bz2
# cd aespipe-v2.4c
# CFLAGS="-O2" LDFLAGS="-static -s" ./configure
# make
# make tests
# cp -p aespipe /boot
Статически соберем утилиту gpg, чтобы она не зависела от библиотек, расположенных в корневом разделе:
# cd /usr/src
# wget ftp://ftp.gnupg.org/gcrypt/gnupg/gnupg-1.4.11.tar.bz2
# tar -xjf gnupg-1.4.11.tar.bz2
# cd gnupg-1.4.11
# patch -p1 </usr/src/loop-AES-v3.6c/gnupg-1.4.11.diff
# CFLAGS="-O2" LDFLAGS="-static -s" ./configure --prefix=/usr --enable-static-rnd=linux
# make
# rm -f /usr/share/man/man1/{gpg,gpgv}.1.gz
# make install
# chown root:root /usr/bin/gpg
# chmod 4755 /usr/bin/gpg
Если каталог /usr/bin находится не на корневом разделе, бинарник gpg придется переместить в каталог /bin:
# cd /usr/bin
# mv gpg ../../bin
# ln -s ../../bin/gpg gpg
Скопируем модуль loop.ko в каталог /boot, чтобы он был доступен до монтирования корневого раздела:
# cp -p /lib/modules/2.6.38-noloop/extra/loop.ko /boot/modules-2.6.38-noloop/
Как и прежде, создадим 65 случайных ключей, которые будут использованы для шифрования корневого раздела:
# umask 077
# head -c 3705 /dev/random | uuencode -m - | head -n 66 | tail -n 65 |\
gpg --symmetric -a >/boot/rootkey.gpg
Подготовим образ initrd. Для этого переходим в каталог с исходниками loop-AES (/usr/src/loop-AES-v3.6c), открываем файл build-initrd.sh в текстовом редакторе и исправляем несколько переменных:
# Использовать метод initramfs/switch_root
# для переключения на зашифрованный корневой раздел
USEPIVOT=2
# Раздел, хранящий каталог /boot
BOOTDEV=/dev/sda1
# ФС boot-раздела
BOOTTYPE=ext3
# Корневой раздел
CRYPTROOT=/dev/sda2
# ФС корневого раздела
ROOTTYPE=ext3
# Метод шифрования (AES128/AES192/AES256)
CIPHERTYPE=AES128
# Клавиатура в режиме UTF-8. Это важно, если
# пароль к ключам содержит нелатинские символы
UTF8KEYBMODE=1
Наконец, установим образ initrd и набор необходимых утилит (losetup, например) в каталог /boot:
# ./build-initrd.sh
Дело осталось за малым: загрузиться с LiveCD (либо другого дистрибутива), создать несколько файлов устройств (которых может не быть до запуска udev) и зашифровать содержимое корневого раздела. Монтируем корневой раздел хост-системы (здесь и далее /dev/hda2):
# mount /dev/hda2 /mnt
Открываем /mnt/etc/fstab и заменяем «/dev/hda2 / ext3 defaults 0 1» на «/dev/loop5 / ext3 defaults 0 1». Два важных замечания: необходимо использовать именно /dev/loop5, – это имя прошито в initrd; в Ubuntu и некоторых других дистрибутивах вместо имени корневого раздела может быть указан его UUID (уникальный идентификационный номер, используется для того, чтобы ядро могло найти корневой раздел, даже если жесткий диск будет подключен к другому каналу/машине). Теперь проверим на существование нескольких файлов устройств (нужны для работы утилит, помещенных в каталог /boot):
# ls -l /mnt/dev/{console,null,zero}
Если таковых не существует - создадим их:
# mknod -m 600 /mnt/dev/console c 5 1
# mknod -m 666 /mnt/dev/null c 1 3
# mknod -m 666 /mnt/dev/zero c 1 5
Отмонтируем корневой раздел:
# umount /mnt
# sync
И смонтируем boot-раздел (mount -r /dev/hda1 /mnt), чтобы воспользоваться утилитой aespipe для шифрования содержимого корневого раздела:
# dd if=/dev/hda2 bs=64k | /mnt/aespipe -e AES128 -K /mnt/rootkey.gpg -G / |\
dd of=/dev/hda2 bs=64k conv=notrunc
Уффф, это все, перезагружаемся и наслаждаемся безопасностью:
# umount /mnt
# sync
# reboot