Содержание статьи
Уже несколько раз мы писали о настройке шифрования дисков в UNIX, но каждый раз концентрировали внимание на инструментах, доступных в Linux, обходя стороной BSD-системы. В этой статье я попытаюсь исправить этот недочет, рассказав о последних нововведениях систем шифрования, появившихся во FreeBSD и OpenBSD.
Ситуация в мире шифрующего ПО для BSD-систем далеко не такая интересная и захватывающая, как в Linux. Здесь нет большого разнообразия сторонних коммерческих систем, нет постоянного флейма на тему уязвимостей тех или иных реализаций, нет сторонних патчей для ядра. Каждая из операционных систем уже давно обладает одной или несколькими реализациями шифрующих подсистем, хорошо документированных в man-страницах и официально поддерживаемых разработчиками ОС. Но даже в таком идеальном мире должны происходить перемены, свидетелями которых мы и стали совсем недавно.
Особо отличились разработчики FreeBSD, которые в конце 2010 года включили в разрабатываемую ветку ОС сразу два нововведения: доработанную реализацию GEOM-класса GELI, который теперь использует современный (и пока еще нескомпрометированный) метод шифрования XTS и стековую шифрующую файловую систему PEFS, предназначенную для шифрования отдельно взятых каталогов. Немного раньше отметились мантейнеры OpenBSD, которые интегрировали поддержку шифрования в драйвер softraid, предназначенный для создания программных RAID-массивов. В этой статье мы рассмотрим все три шифрующие системы, их устройство, возможности и способы применения.
GELI: чертовски классное шифрование
GELI появился еще в шестой версии FreeBSD, но довольно продолжительное время оставался в тени благодаря существованию тысяч устаревших документов и статей, написанных во времена четверкипятерки и рекомендовавших использовать для шифрования другие средства. Сегодня GELI — это FreeBSD-стандарт дискового шифрования, рекомендованный к использованию в абсолютном большинстве случаев. И появившаяся не так давно поддержка метода шифрования XTS только подтверждает это (о том, почему XTS так важен, читай во врезке).
GELI представляет собой класс модульной подсистемы дискового ввода-вывода GEOM, что в переводе на русский означает «специальный модуль, пропускающий через себя запросы ввода-вывода». Модуль можно подсунуть в уже существующий «пирог» из других подобных модулей, получив в результате шифрование данных на любом из уровней этого пирога. Так можно криптануть «голый» жесткий диск, раздел диска, файл, подключенный в качестве блочного устройства, сетевой диск и даже уже зашифрованный диск (подробнее об этом и многих других прелестях GEOM читай в моей статье «Занимательная GEOM'етрия», опубликованной в 96-м номере z). Класс GELI поддерживает несколько алгоритмов шифрования (AES, Blowfish и 3DES) с разной длиной ключа, умеет работать с хардварными криптографическими устройствами, может шифровать ко рневой раздел, поддерживает двойные ключи (например, можно создать личный и корпоративный ключи, и они оба будут использованы для шифрования диска), а также одноразовые ключи (для шифрования разделов с временными данными, таких как /tmp и swap).
Помимо уже упомянутого XTS, не так давно GELI обзавелся возможностью шифровать данные с использованием нескольких ключей, каждый из которых применяется для шифрования своего набора блоков (с применением ключей по кругу), что обеспечивает еще более надежную защиту от различных видов атак (до GELI такая возможность была доступна только в линуксовом loop-aes). Пока обновленный GELI недоступен в стабильной версии FreeBSD, и для его установки придется получить и собрать исходники current-ветки FreeBSD или скачать и установить ISO-образ девятки отсюда: ftp://ftp.freebsd.org/pub/FreeBSD/snapshots/201101/.
Не задействуя новые возможности, его вполне можно использовать в шестой, седьмой и восьмой версиях системы. GELI реализован в виде ядерного модуля geom_eli, который можно загрузить прямо во время работы системы:
# kldload geom_eli.ko
Или заставить делать это в автоматическом режиме:
# echo 'geom_eli_load="YES"' >> /boot/loader.conf
После этого необходимо сгенерировать ключ (salt), который будет нужен для шифрования мастер-ключа, применяемого для шифрования самих данных. Сделать это можно с помощью следующей команды:
# dd if=/dev/random of=~/ad1.key bs=64 count=1
Далее необходимо инициализировать блочное устройство, которое потребуется для хранения зашифрованных данных:
# geli init -s 4096 -K ~/ad1.key -e AES
-a hmac/sha512 -l 256 /dev/ad1
Опция '-s' используется для указания длины блока (лучше использовать значение 4096 (4 Кб), оно совпадает с размером блока файловой системы и поэтому позволит GELI работать с максимальной производительностью), опция '-K' задает путь до сгенерированного ранее ключа, опция '-e' — алгоритм шифрования, '-a' — алгоритм контроля целостности, '-l' — длину ключа для алгоритма шифрования.
В конце указывается подопытное блочное устройство. Замечу, что ни одна из опций не является обязательной, и для выбора дефолтовых значений (256-битный AES без контроля целостности) мы могли бы указать только опцию '-K'.
Кроме того, GELI не позволяет напрямую выбирать режим шифрования, поэтому во всех версиях ОС вплоть до девятой будет использован режим CBC, а в девятой — XTS. Команда запросит пароль, который вместе с ключом будет использован для генерации мастерключа (для доступа к данным понадобится и то, и другое). После этого можно подключить GELI к устройству, чтобы начать его использовать:
# geli attach -k ~/ad1.key /dev/ad1
После ввода пароля в каталоге /dev появится файл /dev/ad1.eli, на котором можно создать файловую систему и смонтировать ее:
# dd if=/dev/random of=/dev/ad1.eli bs=64k
newfs /dev/ad1.eli
mount /dev/ad1.eli /mnt
Размонтирование и отключение GELI происходит в обратном порядке:
# umount /mnt
geli detach ad1.eli
Чтобы вновь получить доступ к зашифрованным данным, достаточно снова набрать две простые команды и ввести пароль:
# geli attach -k ~/ad1.key /dev/ad1
mount /dev/ad1.eli /mnt
Само собой разумеется, что файл-ключ ad1.key лучше не хранить в домашнем каталоге, а поместить на флешку. Чтобы шифрованный диск автоматически монтировался во время загрузки, необходимо изменить несколько конфигов. Файл /boot/loader.conf должен содержать следующие строки:
geli_ad1_keyfi le0_load="YES"
geli_ad1_keyfi le0_type="ad1:geli_keyfi le0"
geli_ad1_keyfi le0_name="/boot/ad1.key"
А файл /etc/fstab нужно изменить так, чтобы имя блочного устройства содержало суффикс «.eli». Например:
/dev/ad1.eli /home ufs rw 2 2
Если шифруемый диск не является системным (не содержит в себе корневой каталог), его автоподключение можно настроить с помощью файла /etc/rc.conf вместо /boot/loader.conf:
geli_devices="ad1"
geli_ad0s1g_fl ags="-k /etc/geli/ad1.key"
geli_ad0s1g_autodetach="NO"
Для шифрования разделов с временными данными GELI позволяет использовать одноразовые ключи, автоматически генерируемые во время подключения устройства:
# dd if=/dev/random of=/dev/ad0s1b bs=64k
geli onetime -d ad0s1b
swapon /dev/ad0s1b.eli
Но если необходимо включать шифрование swap при каждой загрузке, то никаких команд выполнять не требуется. Достаточно просто добавить суффикс «.eli» к имени swap-раздела в /etc/fstab, и загрузочные скрипты сделают всю грязную работу за тебя. Например:
/dev/ad0s1b.eli none swap sw 0 0
PEFS: файлы решают все
Шифрующая файловая система PEFS была добавлена во FreeBSD практически одновременно с обновлением GELI, однако ее назначение совсем иное. По своим характеристикам она гораздо ближе к fuse-ФС encfs (encfs.sf.net), чем к системе шифрования блочных устройств. PEFS работает поверх существующей файловой системы и не требует root-привилегий, что делает ее идеальным решением для защиты пользовательских паролей, ключей, сертификатов и другой личной информации.
PEFS достаточно проста, но в то же время обладает отличными характеристиками:
- работает внутри ядра, что в теории должно сделать ее быстрее аналогов, использующих fuse;
- использует случайные векторы инициализации для каждого файла, благодаря чему две зашифрованные копии одного и того же файла будут выглядеть совершенно по-разному;
- сохраняет размер шифруемого файла (что, однако, можно использовать для предугадывания его содержимого);
- поддерживает произвольное число ключей и смешивание файлов, зашифрованных разными ключами в одном каталоге, а также позволяет сменить ключ для уже зашифрованного файла;
- поддерживает алгоритмы шифрования AES, Camellia и Salsa20;
- поддерживает режим шифрования XTS;
- поддерживает «рассеивания» содержимого файлов;
- работает поверх файловых систем UFS, ZFS и ext2;
- добавляет в систему PAM-модуль для аутентификации пользователей по хранимому в файловой системе ключу.
PEFS уже полностью готова к использованию и успешно проходит тесты fsx, pjdfstest, blogbench и dbench.
Все выполненные разработчиками и энтузиастами замеры показывают примерно двукратное отставание производительности по сравнению с голой файловой системой UFS. Как и GELI, PEFS будет доступна только в девятой версии FreeBSD, но пощупать ее можно будет уже сейчас, необходимо только скачать исходники и собрать их:
# portinstall git
git clone git://github.com/glk/pefs.git pefs
cd pefs
make obj all
make install
make clean
Далее можно протестировать новую разработку. Для этого необходимо создать новый каталог (назовем его secure):
# mkdir ~/secure
Смонтировать PEFS поверх этого каталога. По умолчанию эта операция требует права суперпользователя, но присвоив переменной ядра vfs.usermount значение 1, можно снять такое ограничение (sysctl -w vm.usermount=1).
# pefs mount ~/secure ~/secure
Каталог останется доступным в режиме чтения. Чтобы получить возможность записи с шифрованием, необходимо создать ключ (здесь же можно задать алгоритм шифрования: по умолчанию PEFS использует 256-битный AES и режим шифрования CTR, но мы изменим эти предустановки):
# pefs addkey -a aes256-xts ~/secure
Далее можно проверить, что ключ был добавлен успешно:
# pefs showkeys ~/secure
И протестировать файловую систему:
# echo "Very private data" > ~/secure/test
cat ~/secure/test
Very private data
pefs unmount ~/secure
ls -l ~/secure
OpenBSD: о шифровании в двух томах
Долгое время в OpenBSD существовала только одна стандартная подсистема шифрования дисков под названием SVND (Safe Vnode Disk Driver), реализованная с помощью дополнительной прослойки для подключения дисковых устройств поверх друг друга. Однако в версии 4.4, вышедшей в конце 2008 года, в дополнение к ней появилась более «честная» поддержка шифрования с помощью фреймворка softraid, и пользователи обрели альтернативу, что привело к разгару дискуссий на тему: «что лучше»? Дискуссии длятся до сих пор, но я не собираюсь поддерживать ту или иную реализацию. С практической точки зрения обе системы достойны того, чтобы сосуществовать параллельно и применяться для различных целей.
SVND очень проста в использовании и может быть применена в любой момент к любому устройству или файлу на диске, с ее помощью возможно удобно и быстро создавать крипто-контейнеры, которые так же просто уничтожить и забыть об их существовании.
Система crypto softraid является частью софтверного RAID-драйвера, а потому сложнее в настройке, но более проста в плане сопровождения уже существующих крипто-дисков и защиты от сбоев. Заложенный в нее алгоритм шифрования «чище», безопаснее и производительнее своего аналога из SVND. Никаких других выводов в пользу SVND или crypto softraid у меня нет, поэтому мы рассмотрим оба варианта. Начнем с более простого, SVND. В OpenBSD (как, впрочем, и во всех остальных BSD) есть псевдо-драйвер vnd(4), позволяющий отображать обычные файлы или блочные устройства в новые блочные устройства и, как следствие, монтировать их стандартным образом. SVND представляет собой неболь шую прослойку, встроенную в этот драйвер и позволяющую производить шифрование блочных устройств во время их отображения.
Для работы с такими устройствами применяется утилита vnconfig(8), которая будет нашим основным инструментом. Кроме нее понадобится соль и образ, который будет хранить зашифрованные данные. Их можно создать с помощью команды dd:
# dd if=/dev/arandom of=/tmp/crypto.salt count=1
dd if=/dev/zero of=/tmp/crypto.img bs=1m count=1024
Далее образ можно отобразить в блочное устройство:
# vnconfi g -c -K 2000 -S /tmp/crypto.salt /dev/svnd0c
/tmp/crypto.img
В ответ на запрос вводим пароль и получаем устройство svnd0 в каталоге /dev. Его можно превратить в настоящий диск с помощью записи MBR и таблицы BSD-разделов (на самом деле, это не обязательно, файловую систему можно создать прямо на /dev/svnd0c):
# fdisk -iy svnd0
disklabel -E svnd0
Вводим команды «a a», «w» и «q», на любые вопросы отвечаем нажатием <Enter>. Получаем раздел «a», на нем можно создать новую файловую систему и смонтировать ее:
# newfs /dev/rsvnd0a
mount /dev/svnd0a /mnt
После заливки файлов в контейнер размонтируем его и уничтожим шифрующее блочное устройство:
# umount /mnt
vnconfi g -u svnd0
Смонтировать контейнер снова можно так:
# vnconfi g -c -K 2000 -S /tmp/crypto.salt /dev/svnd0
/tmp/crypto.img
mount /dev/svnd0a /mnt
С механизмом crypto softraid все несколько сложнее. Мы будем использовать его возможности для создания зашифрованной файловой системы защищенного ноута или сервера. Для этого нам понадобится установочный диск OpenBSD версии не ниже 4.4. Загружаемся с компакт-диска. На вопрос инсталлятора о способе загрузки набираем «S» и видим приглашение командного интерпретатора.
Теперь нам нужно разметить диск так, чтобы создать небольшой root-раздел (размером где-то 256 Мб), за ним поместить swap-раздел и добавить к этому основной раздел, который будет зашифрован с помощью softraid. Делаем:
# fdisk -iy wd0
disklabel -E wd0
Вводим команду «a a» и давим <Enter> в ответ на любые вопросы, кроме «size» (в ответ на вопрос «size» вводим «256M»). Это корневой раздел. Далее набираем «a b», указываем размер своп-области (например, «1G»), на остальные вопросы — <Enter>. Вводим «a d», указываем нужный размер основного раздела или нажимаем <Enter> (чтобы использовать весь диск), на вопрос о типе файловой системы (FS type) отвечаем «RAID». Этого требует crypto softraid. Далее вводим стандартные «w» и «q».
Чтобы активировать RAID-массив на разделе wd0d (который на самом деле будет простым зашифрованным томом), используем команду bioctl(8):
# bioctl -c C -r 65536 -l /dev/wd0d softraid0
Дважды вводим пароль. Видим системное сообщение о появлении диска sd0. Теперь можно запустить инсталлятор:
# /install
Отвечаем на стандартные вопросы, выбираем диск wd0 для установки. На вопрос о том, какую часть диска мы хотим использовать (Use (W)hole disk...), набираем «W» — весь диск. На вопрос о раскладке диска (Use (A)uto layout...) отвечаем «C», вновь попадаем в disklabel.
Набираем «m a» (модификация раздела «a»), нажимаем <Enter> на все вопросы, кроме «mount point» ( в ответ на «mount point» указываем «/»). Далее вводим команды «w» и «q». Теперь в системе должен остаться один неинициализированный диск sd0. Это наш крипто-RAID, выбираем его, а в ответ на следующий вопрос нажимаем <Enter>. Вновь попадаем в disklabel, вводим «a a», задаем размер «256M», в качестве точки монтирования указываем /altroot. Создаем дополнительные разделы для точек монтирования /usr, /tmp, /var, /root, /home и так далее. Они будут располагаться на зашифрованном RAID-томе. Это все. Продолжаем отвечать на стандартные вопросы инсталлятора, ждем установки и перезагружаемся.
На этом можно было бы и закончить, но, каким бы странным это ни казалось, при загрузке система начнет засыпать тебя кучей сообщений об ошибке монтирования. Не стоит волноваться, это нормально, просто разработчики еще не успели обновить скрипты инициализации так, чтобы они научились определять наличие зашифрованных разделов и подключать их в автоматическом режиме. Скорее всего, в следующих версиях OpenBSD этот недочет исправят, и тебе потребуется только ввести пароль во время загрузки ОС, однако пока придется выходить из ситуации самостоятельно. Нажми <Enter> и подключи крипто-диск с помощью следующей команды:
# bioctl -c C -l /dev/wd0d softraid0 && exit
Загрузка продолжится в нормальном режиме и все разделы будут без проблем подключены. Чтобы не загружать свой мозг и руки вводом команды каждый раз, ее можно поместить в скрипт и вызывать при загрузке.
NetBSD: старикам здесь место
Хоть эта статья и посвящена новым веяниям в области криптографии, мы никак не могли обойтись без описания того, что нам может предложить NetBSD. У нее тоже есть свой шифрующий драйвер — CGD (Cryptographic Device Driver), который хоть и не блещет количеством различных алгоритмов и методов шифрования, но исправно работает уже очень давно (когда то даже был портирован в OpenBSD).
Для его конфигурирования используется утилита cgdconfig(8), которая позволяет создать зашифрованный диск всего за два шага. Первый шаг — генерирование конфигурационного файла для шифруемого устройства, он нужен для последующих вызовов утилиты (чтобы не вбивать все заново) и скриптов инициализации, подключающих доступные крипто-устройства во время загрузки (мы не будем рассматривать этот вариант). Создадим конфиг для флешки sd0:
# cgdconfi g -g -o /etc/cgd/sd0 aes-cbc
Далее сконфигурируем псевдоустройство cgd0, которое будет выступать в качестве шифрующего бэк-энда к флешке, представленной устройством /dev/sd0:
# cgdconfi g cgd0 /dev/sd0
После ввода пароля устройство будет готово к использованию. На нем можно создать файловую систему и смонтировать ее:
# newfs /dev/cgd0
mount /dev/cgd0 /mnt
По окончании работы размонтируем файловую систему и отключаем устройство cgd0:
# umount /dev/cgd0
cgdconfi g -u cgd0
Чтобы вновь подключить флешку, выполняем две команды:
# cgdconfi g cgd0 /dev/sd0
mount /dev/cgd0 /mnt
Выводы
BSD-системы не стоят на месте и постоянно развиваются. Технологии, считавшиеся стандартом несколько лет назад, отмирают, им на смену приходят новые. Отрадно видеть, что системы криптозащиты данных прогрессируют так же быстро. Пользуясь BSD, ты всегда будешь уверен в сохранности своих данных.
XTS: в чем профит?
Первые криптографические системы использовали простое поблочное шифрование данных с помощью заданного пользователем ключа. Блок данных просто извлекался из памяти, шифровался и записывался обратно, то же самое происходило со следующим блоком и всеми остальными. Практически сразу была найдена проблема такого подхода, которая заключалась в очень простом способе предугадывания хранимых в контейнере данных через сравнение разных шифрованных блоков. Чтобы решить проблему, были придуманы разные режимы шифрования, которые позволяли сделать результат шифрования даже одинаковых блоков данных уникальным. Самым распространенным из них стал режим CBC (Cipher Block Chaining), который побитно XOR'ил каждый следующий шифруемый блок с предыдущим так, чтобы на выходе получался уникальный результат. Однако у CBC тоже было несколько проблем, которые позволяли применить против него различные виды атак, таких как multiscan, watermarking и атак на подмену.
Другие изобретенные режимы шифрования также оказались в той или иной мере подвержены этим и другим видам атак, и сегодня осталось всего несколько режимов, уязвимость которых еще не была доказана. И самый эффективный из них носит имя XTS.
В стиле Unix-way
Ключ GELI можно спокойно разделить на несколько частей с помощью команды split(1), а затем объединить их и передать команде geli на стандартный вход:
# cat keyfi le1 keyfi le2 keyfi le3 | geli init -K - /dev/da2
Зашифрованная виртуальность
В отличие от всех остальных представленных систем, OpenBSD производит шифрование свопа по дефолту:
% sysctl -a | grep swapenc | head -n1
vm.swapencrypt.enable=1