АЛЕКСАНДР ПОХАБОВ
Шифрование данных в Linux – новый взгляд на аппаратные ключи
«Кто владеет информацией, тот владеет миром» – всем известное изречение Уинстона Черчилля. Вот и мы, впустив в свой дом компьютеры, доверяем им хранение части нашего внутреннего мира, который не должен предстать перед кем-либо, кроме самих владельцев. Что хранят миллионы жестких дисков по всему свету? От дружеской email-переписки и домашних фотоальбомов до закрытой от посторонних глаз информации, имеющей статус государственной и коммерческой тайны. Но кроме «винчестеров» имеются и другие носители, количеством и объемом хранимых данных превосходящие своих братьев, находящихся внутри корпусов современных ПК. Не стоит также недооценивать значимость той же переписки, ведь статью 23 п.2 Конституции РФ еще никто не отменял.
Но, к сожалению, преступный мир не чтит государственных законов. Огромное количество персональных компьютеров похищается прямо из дома, ноутбуки «забываются» командированными сотрудниками, которые также часто становятся жертвами грабежа, мобильные носители могут быть просто потеряны по пути из точки А в точку Б. Как можно в таких случаях быть уверенным в том, что находящиеся на утерянных носителях данные не попадут в руки заинтересованных в них лиц? А ведь подавляющее большинство информации хранится на жестких дисках, CD, DVD и т. д. в «чистом» виде, и ничто не стеснит злоумышленника в его действиях.
В Интернете, да и в печатных изданиях широко освещены решения по шифрованию конфиденциальной информации с использованием пары ключей. Следуя авторам большинства таких статей, пользователи размещают ключи на все тех же простых носителях, таких как FLASH-накопители и флоппи-диски (последние к тому же имеют свойство отказывать в самый неподходящий момент). И тут уже подбор верного passphrase к легкодоступным ключам – дело техники.
Нашей задачей будет если не предотвратить возможность восстановления злоумышленником данных из зашифрованного раздела полностью, то на порядки усложнить его работу. В этом нам поможет аппаратный ключ, хранящий сертификаты и ключи в своей защищенной энергонезависимой EEPROM-памяти. Его «прошивка» описана в статье «Железный login: ломаем зубы грубой силе», №12, 2004 г.).
Поскольку я имею дело с домашней рабочей станцией под управлением Gentoo Linux, а не с промышленным сервером, то позволил себе использовать dm-crypt вместо crypto-loop (подразумевает ядро начиная с версии 2.6.4). Я доверился мэйнтейнеру cryptoapi Fruhwirth Clemens, выражавшему свои доводы в пользу dm-crypt в LKML, что и вам советую.
Впервые поддержка dm-crypt появилась в ядре 2.6.4, но несмотря на четный минор, в широком кругу Linux-сообщества считается авантюрой перевод работающих серверов на новую ветвь ядра. В 2.4.-ядрах Device Mapper Support недоступен. Из преимуществ dm-crypt перед cryptoloop бегло можно назвать независимость от инструментов пространства пользователя (linux-util), использование mempool, и отсутствие необходимости в правке /etc/fstab . Более подробную информацию вы можете найти на сайте проекта: http://www.saout.de/misc/dm-crypt.
Принцип действия таков: мы поместим зашифрованный публичный ключ в начало защищаемого раздела, при входе в систему определенного пользователя (обладающего аппаратным ключом и знающим PIN), зашифрованный ключ будет прочитан во временный файл, расшифрован pkcs15-crypt и передан в качестве параметра cryptsetup для определения зашифрованного раздела (во избежание удаления ключа из начала раздела cryptsetup вызывается с параметром --offset=SECTORS), после чего содержащий копию ключа временный файл будет удален. Далее мы отформатируем новый раздел (для первого использования), смонтируем его и перенесем в него копию домашнего каталога пользователя.
Все это, за исключением форматирования и переноса из резервной копии содержимого $HOME, будет делаться автоматически с помощью pam_mount в момент регистрации целевого пользователя в системе.
Убедитесь, что в ядре присутствует все необходимое для дальнейшей работы. Ниже приведена выдержка из моего /usr/src/linux/.config:
CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
CONFIG_CRYPTO_AES_586=y
Также проверьте, установлены ли:
sys-fs/cryptsetup
dev-libs/openssl
dev-libs/openct
sys-fs/device-mapper
Как бы то ни было, установленный не из CVS-репозитория opensc придется удалить, так как только в CVS-версии pkcs15-crypt имеется опция --raw, используемая мною в данном примере. В стабильных версиях вывод pkcs15-crypt не будет распознан как параметр cryptsetup. Данная опция была добавлена 21 августа 2004 года и не была включена в релиз стабильной версии OpenSC 0.9.4, вышедший позже – 31 октября 2004. Будет ли она в следующем релизе, я сказать не могу.
# emerge unmerge opensc
Установка opensc из CVS:
# cvs -d :pserver:cvs@cvs.opensc.org:/cvsroot login
Примечание: вместо ввода пароля нажмите .
# cvs -z3 -d :pserver:cvs@cvs.opensc.org:/cvsroot co opensc
# cd opensc
# ./bootstrap
# ./configure --prefix=/usr --exec-prefix=/usr --with-pam-dir=/путь_к/libpam --with-pam --with-openct=/путь_к/libopenct
--with-openssl=/путь_к/openssl
Проверьте вывод ./configure в STDOUT, необходимые опции, такие как OpenSSL support, OpenCT support и PAM support должны быть включены (отмечены как «yes»).
# make
# make install
Если при конфигурировании ядра вы не включили в ядро dm-crypt (Multi-device support (RAID and LVM) ® Device Mapper Support и Crypt Target Support) статически, то подгрузите модуль:
# modprobe dm_crypt
Создайте любым удобным для вас способом резервную копию пользовательского домашнего каталога. У меня он автоматически архивируется по расписанию и практически ничего, кроме ~/.bash_history, в нем не изменяется. Резервная копия понадобится нам для переноса всего ее содержимого во вновь созданный и смонтированный в привычный пользовательский $HOME (прописанный в /etc/passwd) защищенный раздел, проще говоря – для миграции. По моему личному мнению резервирование домашних каталогов – просто хороший тон.
Специально для простоты и удобства я создал в корне директорию /crypt и работал в ней.
# mkdir /crypt
# cd /crypt
# chmod 700 /crypt
# chown chiko:root /crypt
где chiko – пользовательский login.
Далее читаем публичный ключ с прошитого аппаратного и шифруем его перед помещением в создаваемый раздел:
# pkcs15-tool --read-public-key 45 > mykey.pub
# dd if=/dev/random of=/crypt/key.plain bs=1 count=96
96+0 records in
96+0 records out
|
# openssl rsautl -encrypt -pubin -inkey mykey.pub -in /crypt/key.plain -pkcs -out /crypt/key
# rm /crypt/key.plain
# rm /crypt/mykey.pub
Вывод pkcs15-crypt в STDOUT не радует глаз, зато теперь известно, что ключ расшифрован и может быть передан в качестве параметра:
# pkcs15-crypt --raw --pkcs1 --decipher -k 45 -i /crypt/key
Можно убедиться в преимуществе CVS-версии opensc, вызвав pkcs15-crypt без опции --raw.
В своем примере я защищаю домашнюю директорию, находящуюся на USB-Flash накопителе (/dev/sda1) объемом ~244 Мб, вы же можете использовать любой раздел диска. Не поленитесь проверить размер вашего домашнего каталога – он не должен превышать вместимости раздела.
# dd if=/dev/urandom of=/dev/sda1 bs=1M count=240
245+0 records in
244+0 records out
|
Размещаем в начале раздела ключ :
# dd conv=notrunc if=/dev/zero of=/dev/sda1 bs=1024 count=1024
1024+0 records in
1024+0 records out
|
# dd conv=notrunc if=/crypt/key of=/dev/sda1 bs=1
128+0 records in
128+0 records out
|
Проверим, читается ли он безошибочно из рассматриваемого раздела, для этого сравним выводы md5sum до копирования ключа обратно в /crypt :
# md5sum /crypt/key
8fc7975ed38f56cabe507a93baaa177a /crypt/key |
# rm /crypt/key
и после:
# dd if=/dev/sda1 bs=1 count=128 of=/crypt/key
128+0 records in
128+0 records out
|
# md5sum /crypt/key
8fc7975ed38f56cabe507a93baaa177a /crypt/key |
Отлично, записанный в начало раздела ключ читается безошибочно. Готовим раздел к переносу пользовательских данных из резервной копии:
# pkcs15-crypt --raw --pkcs1 --decipher -k 45 -i /crypt/key | cryptsetup --hash=plain --cipher=aes --key-size=256 --offset=2048 create mynewhome /dev/sda1
На данном шаге форматируется новый раздел. Я предпочел ext2fs, но никому не навязываю своего решения:
# mkfs.ext2 /dev/mapper/mynewhome
Забавно наблюдать за пользователями Windows, пытающимися посмотреть содержимое FLASH-накопителя и предложение отформатировать его.
Смонтируем:
# mount /dev/mapper/mynewhome /home/chiko
Перенесем из резервной копии содержимое домашнего каталога пользователя chiko и сделаем его владельцем командой:
# chown –R chiko:root /home/chiko
В моей системе пользователь chiko не является членом группы root, в нее входит лишь одноименный пользователь. Приходилось видеть права доступа rwxr-x-- на домашних каталогах пользователей, входящих в группу, насчитывающую несколько представителей. Права на чтение и просмотр каталога были выставлены именно на ту самую группу, соответственно, в ~/.bash_history пользователя vasya встречалось что-то вроде cp -R /home/nikolay ~/kolya_lamer. Проследите за тем, чтобы никто не мог перейти ваш $HOME, если же необходимо впустить кого-нибудь, не стоит рекурсивно отдавать все и всем.
Не забывайте, что ~/.eid/authorized_certificates должен быть доступен для чтения и в неподключенном в точку /home/chiko (пользовательский $HOME, указанный в /etc/passwd) новом разделе и в смонтированном. Последнее уже выполнено при восстановлении из резерва всей копии домашнего каталога.
# umount /home/chiko
Резервная копия домашнего каталога имеется, после успешного монтирования зашифрованного раздела можете распорядиться им по своему усмотрению. Я оставил в несмонтированной точке /home/chiko лишь /.eid/authorized_ certificates, а все остальное просто удалил.
# cryptsetup remove mynewhome
# rm /crypt/key
Устанавливаем pam_mount. Для большинства дистрибутивов эта задача тривиальна.
Для пользователей Gentoo Linux имеется ebuild, скачать можно здесь: http://bugs.gentoo.org/attachment.cgi?id=51530& action=view.
Установка с помощью ebuild в Gentoo считается идеологически верной, но при желании можно взять исходники pam_ mount на домашней странице: http://www.flyn.org/projects/pam_mount и установить вручную. Когда он будет включен в portage-tree и будет ли вообще включен, мне, к сожалению, неизвестно.
После установки pam_mount необходимо отредактировать два файла: конфигурационный /etc/security/pam_ mount.conf и скрипт /sbin/mount.crypt.
Лично я потратил много времени на редактирование и доводку скрипта /sbin/mount.crypt, установленного с помощью вышеназванного ebuild, но раздел не монтировался. На помощь пришел mount.crypt от дистрибутива Debian, который можно взять здесь: http://bugs.gentoo.org/attachment.cgi? id=49305.
Скачайте и замените им имеющийся /sbin/mount.crypt. Поскольку я не могу рассмотреть данный скрипт в каждом отличном от Gentoo дистрибутиве, рекомендую загрузить его всем и как минимум проверить с помощью diff различия от поставляемого с вашей системой с предлагаемым мной.
Приступим к конфигурированию. Ниже привожу листинги /etc/security/pam_mount.conf и /sbin/mount.crypt.
#cat /etc/security/pam_mount.conf
debug 0
# При возникновении ошибок будет полезно иметь вывод: debug 1
options_allow nosuid,nodev,loop,encryption
# Здесь и строкой ниже по желанию
options_require nosuid,nodev
lsof /usr/sbin/lsof %(MNTPT)
fsck /bin/true
# Для FLASH-накопителя с ext2fs не счел нужным проверять fsck.ext2
losetup /bin/true [пс]
unlosetup /bin/true [пс]
cifsmount /bin/mount -t cifs //%(SERVER)/%(VOLUME) %(MNTPT) -o "username=%(USER)%(before="," OPTIONS)"
smbmount /bin/mount -t smbfs //%(SERVER)/%(VOLUME) %(MNTPT) -o "username=%(USER)%(before="," OPTIONS)"
ncpmount /bin/mount -t ncpfs %(SERVER)/%(USER) %(MNTPT) -o "pass-fd=0,volume=%(VOLUME)%(before="," OPTIONS)"
umount /bin/umount %(MNTPT)
lclmount /sbin/mount.crypt %(VOLUME) %(MNTPT) -o %(OPTIONS)
# Не забудьте заменить /sbin/mount.crypt скриптом из Debian
cryptmount /sbin/mount.crypt %(VOLUME) %(MNTPT) -o %(OPTIONS)
nfsmount /bin/mount %(SERVER):%(VOLUME) "%(MNTPT)%(before="-o " OPTIONS)"
pmvarrun /usr/sbin/pmvarrun -u %(USER) -d -o %(OPERATION)
# Строка, описывающая имя пользователя, раздел, точку и опции монтирования
volume chiko crypt - /dev/sda1 /home/chiko loop,cipher=aes - -
Весь листинг /sbin/mount.crypt слишком велик, чтобы привести его на страницах печатного издания, поэтому добавленные в него блоки буду выделять красным:
# В самом начале добавьте строку read PIN
LOSETUP=/sbin/losetup
CRYPTSETUP=/bin/cryptsetup
MOUNT=/bin/mount
OPTIONS=""
read PIN # Таким образом передаем PIN в pkcs15-crypt
USAGE="dev dir [-o options]
# Найдите и закомментируйте, как в примере, четыре следующие строки:
#HASHOPT="ripemd160"
#if [ -n "$HASH" ]; then
# HASHOPT="$HASH"
#fi
# Вместо них подставьте свои:
HASHOPT=""
if [ ! -z "$HASH" ]; then
HASHOPT="-h $HASH"
fi
KEYSIZEOPT="256"
if [ -n "$KEYSIZE" ]; then
KEYSIZEOPT="$KEYSIZE"
fi
# Сразу же после KEYSIZEOPT-секции добавляем три новых строки:
dd if=/dev/sda1 bs=1 count=128 of=/crypt/key
/usr/local/bin/pkcs15-crypt --raw -p $PIN --pkcs1 --decipher -k 45 -i /crypt/key | $CRYPTSETUP --cipher=aes --hash=plain
--key-size=256 --offset=2048 create $DMDEVICE $DEVICE
rm /crypt/key
# Следующую строку из оригинала закомментируем, так как выше используем собственный аналог:
#$CRYPTSETUP -c $CIPHEROPT -h $HASHOPT -s $KEYSIZEOPT create $DMDEVICE $DEVICE
Пример скрипта /sbin/mount.crypt можно скачать на сайте журнала http://samag.ru в разделе «Исходный код». В большинстве случаев придется изменить только /dev/sda1 и путь к директории хранения временного файла на необходимые вам значения.
Есть риск, что во время выполнения другими пользователями ps в ее вывод может попасть наш PIN, поэтому рекомендуется запретить пользователям просматривать список чужих процессов с помощью grsecurity (см. одноименную статью Кирилла Тихонова в журнале №9, 2004 г.).
Остается подправить /etc/pam.d/login :
# cat /etc/pam.d/login
#%PAM-1.0
auth optional pam_mount.so
auth required /usr/local/lib/security/pam_opensc.so use_first_pass
session optional pam_mount.so use_first_pass
account required /lib/security/pam_stack.so service=system-auth
session required /lib/security/pam_stack.so service=system-auth
Пробуем зарегистрироваться как chiko. Если вы верно следовали моему описанию, то должны увидеть что-то наподобие этого (при выставленном в /etc/security/pam_ mount.conf значении debug 1):
pam_mount: reading options_allow...
pam_mount: reading options_require...
pam_mount: back from global readconfig
pam_mount: per-user configurations not allowed by pam_mount.conf
pam_mount: real and effective user ID are 0 and 0.
pam_mount: checking sanity of volume record (/dev/sda1)
pam_mount: about to perform mount operations
pam_mount: information for mount:
pam_mount: --------
pam_mount: (defined by globalconf)
pam_mount: user: chiko
pam_mount: server:
pam_mount: volume: /dev/sda1
pam_mount: mountpoint: /home/chiko
pam_mount: options: loop,cipher=aes
pam_mount: fs_key_cipher:
pam_mount: fs_key_path:
pam_mount: use_fstab:
pam_mount: --------
pam_mount: checking to see if /dev/mapper/_dev_sda1 is already mounted at /home/chiko
pam_mount: checking for encrypted filesystem key configuration
pam_mount: about to start building mount command
pam_mount: command: /crypt/mount.crypt /dev/sda1 /home/chiko -o loop,cipher=aes /home/chiko
pam_mount: mount errors (should be empty):
pam_mount: 128+0 records in
pam_mount: 128+0 records out
pam_mount: waiting for mount
pam_mount: clean system authtok (0)
pam_mount: command: /usr/sbin/pmvarrun -u chiko -d -o 1
pam_mount: pmvarrun says login count is 1
pam_mount: done opening session
Вот и долгожданное приглашение! Проверьте наличие в новой домашней директории своих перенесенных из резервной копии данных и вывод команды mount.
# mount | grep mapper
/dev/mapper/_dev_sda1 on /home/chiko type ext2 (rw) |
Как успел заметить опытный читатель, пользуясь описанным способом, можно шифровать не только пользовательские домашние каталоги.
Со страниц журнала желаю вам удачи, и пусть ваши конституционные права остаются незыблемыми.
Ссылки:
- http://www.flyn.org/projects/pam_mount.
- http://www.saout.de/misc/dm-crypt.
- http://opensc.org.