Издательский дом ООО "Гейм Лэнд"ЖУРНАЛ ХАКЕР 129, СЕНТЯБРЬ 2009 г.

Шифруемся помаленьку. Шифрование диска в Linux с помощью loop-AES

Евгений Зобнин (zobnin@gmail.com)

В нашем повсеместно мобилизованном мире потерять информацию проще простого: выронил флешку из кармана, украли телефон, забыл ноутбук. Все это случается ежедневно и может сильно подпортить жизнь владельцу устройства, если он заранее не позаботился о защите важной информации. А защитить ее можно только двумя способами: надежно спрятать или зашифровать.

Для Linux в разные времена было разработано множество различных средств шифрования дисковых разделов. С ходу можно вспомнить несколько проектов: коммерческий TrueCrypt, показывающий отличную производительность в Windows, но отстающий ото всех остальных в Linux; встроенный в ядро и постоянно критикуемый за нестойкость dm-crypt; элегантный, неторопливый (поскольку выполняется в окружении пользователя и работает поверх файловой системы) encfs. В стороне от списка зачастую оказывается один из старейших, производительных и надежных шифрующих Linux-драйверов loop-AES.

Драйвер loop-AES

Сторонний драйвер 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-AES состоит из четырех компонентов: модифицированного драйвера loop.ko, набора патчей для системных утилит, патча для ядра Linux и коллекции модулей, обеспечивающих поддержку алгоритмов шифрования Blowfish, Serpent и Twofish. Первые два компонента нам понадобятся в любом случае, а вот третий и четвертый совсем не обязательны. Во-первых, драйвер можно собрать и отдельно от ядра, а во-вторых, используемый по умолчанию алгоритм AES - один из лучших. Менять его на какой-то другой не имеет смысла.
В качестве подопытной системы будем использовать дистрибутив Ubuntu 9.04, построенный на ядре 2.6.28.9, но главное - учитывать номера версий необходимого ПО и следовать инструкциям.

Для начала получим исходники ядра Linux (от 2.0 до 2.6.30, драйвер работает с любым из них). Для 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.28.tar.bz2
# cp /boot/config-2.6.28-11-generic ./linux-source-2.6.28/.config
# cd ./linux-source-2.6.28
# 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.28.9-noloop*

Рецепт для всех остальных дистрибутивов:

# make
# make modules_install
# cp arch/i386/boot/bzImage /boot/vmlinuz-2.6.28.9-noloop

Редактируем /boot/grub/grub.conf, чтобы показать загрузчику новое ядро (для Ubuntu не требуется), и отправляем комп на перезагрузку.

Установка

Загрузившись с новым ядром, приступаем к установке драйвера loop-AES:

# 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.2g
# make clean
# make LINUX_SOURCE=/usr/src/linux-source-2.6.28

Подчищаем исходники ядра:

# cd /usr/src/linux-source-2.6.28
# make clean

И переходим к сборке и установке модифицированных утилит mount, umount, losetup, swapon, swapoff. Все они распространяются в пакете util-linux, но в стандартном виде не подходят для управления шифрованными дисковыми разделами и swap-областями. Поэтому их придется пропатчить:

# cd /usr/src
# wget http://www.kernel.org/pub/linux/utils/util-linux-ng/v2.15/util-linux-ng-2.15.1.tar.bz2
# tar -xjf util-linux-ng-2.15.1.tar.bz2
# cd util-linux-ng-2.15.1
# patch -p1 </usr/src/loop-AES-v3.2g/util-linux-ng-2.15.1.diff
# CFLAGS="-O2 -Wall" ./configure
# make SUBDIRS=mount

На момент написания статьи уже существовал пакет util-linux-ng версии 2.16, но я выбрал 2.15.1 просто потому, что версия loop-AES, доставшаяся мне, включала патч только для util-linux-ng-2.15.1. Это очень важный момент, который нужно учитывать во время патчинга утилит.

После того, как утилиты будут собраны, установим их в систему (весь пакет устанавливать опасно, поэтому мы вручную скопируем только необходимые утилиты):

# 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.2g
# 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).

1. Создадим 65 случайных ключей и зашифруем их с помощью gpg:

$ head -c 3705 /dev/random | uuencode -m - | head -n 66 | tail -n 65
| gpg --symmetric -a >/media/usbstick/keyfile.gpg

Вводим пароль для доступа к файлу ключей.

2. Заполним раздел случайными данными. Для этого создадим псевдо-устройство /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

3. Добавим в /etc/fstab следующую запись:

/dev/sda2 /mnt ext3 defaults,noauto,loop=/dev/loop2,encryption=AES128,gpgkey=/media/usbstick/keyfile.gpg 0 0

4. Теперь на устройстве можно создать файловую систему:

# losetup -F /dev/loop2
# mkfs -t ext3 /dev/loop2
# losetup -d /dev/loop2

С помощью флага '-F' мы заставили losetup взять всю необходимую ей информацию из файла /etc/fstab, затем создали на псевдо-устройстве файловую систему ext3 и удалили его.

5. Наконец, примонтируем файловую систему:

# 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-устройства поверх корневого раздела еще до фактической загрузки системы.

1. Первое, что необходимо сделать, – это скачать и установить 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

2. Также нам понадобится утилита aespipe, с помощью которой мы зашифруем существующие на корневом разделе данные, не потеряв их:

# cd /usr/src
# wget http://loop-aes.sourceforge.net/aespipe-latest.tar.bz2
# cd aespipe-v2.3e
# CFLAGS="-O2" LDFLAGS="-static -s" ./configure
# make
# make tests
# cp -p aespipe /boot

3. Статически соберем утилиту gpg, чтобы она не зависела от библиотек, расположенных в корневом разделе:

# cd /usr/src
# wget ftp://ftp.gnupg.org/gcrypt/gnupg/gnupg-1.4.9.tar.bz2
# tar -xjf gnupg-1.4.9.tar.bz2
# cd gnupg-1.4.9
# patch -p1 </usr/src/loop-AES-v3.2g/gnupg-1.4.9.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

4. Скопируем модуль loop.ko в каталог /boot, чтобы он был доступен до монтирования корневого раздела:

# cp -p /lib/modules/2.6.28.9-noloop/extra/loop.ko /boot/modules-2.6.28.9-noloop/

5. Как и прежде, создадим 65 случайных ключей, которые будут использованы для шифрования корневого раздела:

# umask 077
# head -c 3705 /dev/random | uuencode -m - | head -n 66 | tail -n 65
| gpg --symmetric -a >/boot/rootkey.gpg

6. Подготовим образ initrd. Для этого переходим в каталог с исходниками loop-AES (/usr/src/loop-AES-v3.2g), открываем файл build-initrd.sh в текстовом редакторе и исправляем несколько переменных:

Настройка 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

Отредактируем конфигурационный файл grub (/boot/grub/menu.lst), чтобы запись о нашем ядре выглядела примерно так:

# vi /boot/grub/menu.lst

title Ubuntu 9.04, kernel 2.6.28.9-noloop
root (hd0,0)
kernel /boot/vmlinuz-2.6.28.9-noloop
initrd /initrd.gz

Наконец, установим образ initrd и набор необходимых утилит (losetup, например) в каталог /boot:

# ./build-initrd.sh

7. Дело за малым: загрузиться с 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

Заключение

Как видишь, loop-AES не так уж и сложен в установке и достаточно прост в использовании (за исключением четвертого сценария, конечно). С помощью этого незамысловатого драйвера можно зашифровать swap, разделы, файлы, флеш-накопители и даже CD-ROM. В пакете с исходниками драйвера ты найдешь подробное руководство, описывающее, кроме всего прочего, процесс настройки шифрования файловой системы загрузочного флеш-брелка и создания безопасного LiveCD.

DVD

Для большего удобства мы собрали все необходимые команды в файл im_too_lazy_to_type_it.txt. Вместо набора команд тебе будет достаточно делать copy'n'paste.

INFO

Описанная в статье утилита aespipe - это отличный инструмент, который можно использовать для получения доступа к зашифрованному устройству отовсюду, например из FreeBSD.

В отличие от других систем шифрования, драйвер loop-AES поддерживает прямую и обратную совместимость с более ранними ядрами (вплоть до ветки 2.0) и может работать с томами, зашифрованными еще самыми первыми версиями драйвера.

В качестве нижележащего устройства ты можешь использовать не только раздел жесткого диска, но и обычный файл, на котором создана нежурналируемая ФС.

WARNING

Во многих дистрибутивах утилиты и драйвер loop-AES можно установить средствами пакетного менеджера, однако ядро придется пересобирать в любом случае.

Содержание
ttfb: 7.152795791626 ms