Правдоподобное отрицание с испольованием LUKS


Опубликовано:   |   Read in English   |   Leer en español   |   Больше записей о LUKS security software

В этой статье я расскажу вам, как создать скрытый криптоконтейнер стандартными средствами ОС Linux (LUKS и cryptsetup). Встроенные фишки LUKS'а (такие, как использование внешних заголовков и размещение реальных данных по заданному смещению) позволяют пользователю получить доступ к данным, скрытым внутри существующего контейнера, а также отрицать существование подобных данных.

UPD[31/05/2014]: Поскольку этот пост был готов ещё месяц назад, тогда я даже не мог представить настолько странную и неожиданную смерть проекта TrueCrypt. Ну да, возможно, он ещё не совсем помер, посмотрим… Тем не менее, в этом тексте я решил оставить все ссылки на TrueCrypt как есть.

Что такое «правдоподобное отрицание»?

Вы можете найти весьма длинное и подробное описание этого понятия в Википедии: http://en.wikipedia.org/wiki/Plausible_deniability. Если коротко, это значит, что вы можете обладать чем-то (или могли сделать что-то), наличие чего не может быть никем заподозрено или доказано (если в этом не признаться самостоятельно, конечно). И впоследствии вы можете отрицать наличие (или факт совершения) этого чего-то, если кто-то захочет вас обвинить, поскольку (повторюсь) этот факт недоказуем. Ну например, если ребёнок пнул под зад своего маленького брата, и брат пошёл искать справедливости у родителей, что в этом случае произойдёт?

Ну… Как бы ничего не произойдёт. Потому что этот чувак будет отнекиваться, а родители, формально говоря, не смогут его поймать за руку (поскольку, во-первых, тупо нет свидетелей, а во-вторых, младший братец может вести свою грязную игру). Таким образом, никого не накажут. Ну или накажут обоих на всякий пожарный. Это как раз был пример использования возможности правдоподобного отрицания ребёнком, склонным к агрессии. Но мы-то с вами, безусловно, белые и пушистые, и будем использовать скрытые контейнеры исключительно в целях защиты своих персональных данных от плохих парней. Так ведь? Безусловно, «что такое „хорошо”, и что такое „плохо”» — это отдельный вопрос… Однако, ближе к делу.

Общая идея реализации

Предположим, мы хотим сохранить некие важные данные внутри зашифрованного файла. В общем случае мы будем использовать какую-то программу криптозащиты, которая будет делать за нас всю грязную работу. Возможно, мы захотим работать с зашифрованным файлом как с виртуальным диском, и это значительно сужает число потенциальных кандидатов. Однако, есть одно «но». Практически все подобные программы работают с файлом как с одним куском зашифрованных данных. Поясню: у пользователя обычно есть один пароль (и, быть может, несколько «запасных») для всех данных внутри контейнера. Это означает наличие как минимум одного слабого звена: пароля на контейнер. Я не хочу упоминать о том, что пароль должен быть криптографически надёжным, поскольку это прописная истина. Я имею в виду, что если пользователь по какой-то причине сдаст этот пароль (например, под давлением), все данные будут прочитаны. И этот факт мне кажется печальным и совершенно неправильным…

Хотя вообще-то надежда есть. :) Например, существует такая программа, как TrueCrypt, которая является достаточно умной. Пользователь может создать в одном файле два контейнера: один «подставной» с некоторым количеством «запрещённых», но относительно безопасных файлов, а другой — настоящий, с данными, которые не должны засветиться ни в коем случае. Таким образом, TrueCrypt запрашивает два разных пароля, когда пользователь хочет создать подобный «двойной» контейнер. При работе пользователь вводит только один пароль для «настоящей» части и работает с ней. В том случае, если под давлением внешних обстоятельств пользователь вынужден раскрыть содержимое контейнера третьим лицам, он просто вводит другой пароль, и TrueCrypt открывает «фальшивку». Я подчёркиваю (и это действительно важно), что не существует возможности доказать наличие скрытой части, если исследователь не знает соответствующего пароля.

А теперь давайте быстренько разберёмся, как работает это барахло… На самом деле всё очень просто. Софт делит файл-контейнер на две (вообще говоря, неравные) части. Первая часть, которая может быть относительно небольшой, содержит специально подготовленные данные; вторая — настоящие. Соответственно, программа должна уметь работать с двумя различными заголовками (конфигурациями) для двух разных частей, а также уметь выбирать, какую часть расшифровывать в зависимости от введённого пользователем пароля. А это, надо сказать, не самая тривиальная часть работы. Ну просто потому, что «официально» должна быть видна только одна, «фальшивая», конфигурация: если у контейнера есть стандартный заголовок, это должен быть только «фальшивый» заголовок; если параметры контейнера хранятся в отдельном конфиге, этот конфиг должен позволять расшифровать только «фальшивую» часть. И после расшифровки «фальшивой» части не должно появиться ни одного намёка на наличие реальной. Они должны быть абсолютно независимыми. Более того, когда открыта «фальшивая» часть, софт должен показывать полную ёмкость крипто-контейнера, даже в том случае, когда объём этой части намного меньше.

Так что там про LUKS-то?

Ну тут у нас есть хорошие новости и… эм… ещё боле хорошие новости.

Хорошие новости заключаются в том, что cryptsetup умеет расшифровывать и монтировать тома, созданные TrueCrypt'ом. Только для чтения, впрочем, но это ерунда. Поскольку есть новости и получше. А именно, мы можем создавать «скрытые» контейнеры исключительно средствами cryptsetup'а. Более того, эта утилита позволяет создать любое количество «скрытых» частей. Естественно, в разумных пределах. И вот каким образом это можно сделать.

Но перед тем, как продолжить,

ОГРОМНОЕ ЖИРНОЕ СТРАШНОЕ ПРЕДУПРЕЖДЕНИЕ!!!

  • Всё, что описано ниже, может стать причиной необратимой потери данных.
  • В вашей стране может быть запрещено использование сильной криптографии, так что вас могут посадить не за реальную информацию, а просто за наличие крипто-контейнера, который найдут на вашем винте.
  • Криптография может защитить ваши данные, однако она не защитит вас от пыток. Скрытый контейнер может помочь сохранить ценную информацию, но вы не сможете отрицать его наличие в случае предательства или доноса.
  • Ребята, которых заинтересовали ваши зашифрованные данные, могут оказаться не настолько тупыми, как вы ожидали. Даже если они не смогут доказать наличие скрытой части контейнера, они вполне могут запереть вас в одной камере с матёрыми уголовниками, и через пару суток вы вспомните все пароли ко всем скрытым данным.
  • Если у вас есть близкие люди (девушка/парень, родственники, друзья), они точно так же могут стать мишенью для жёсткого прессинга. И это наверняка поможет значительно быстрее вспомнить вообще всё, включая то, чего вы даже и не знали.

Так что лучше дважды подумайте, насколько информация ценнее вашей жизни и жизни ваших близких. И сделайте бэкап. Просто на всякий случай.

Ну ладно, я вас предупредил, поехали дальше.

Так вот, man cryptsetup способен рассказать нам множество интересных подробностей о параметрах командной строки этой утилиты. Ну например, давайте глянем на опцию --header:

--header <устройство или файл‚ содержащие заголовок LUKS>
  Использовать внешнее (отдельное) устройство метаданных или файл для хранения заголовка LUKS. Эта опция позволяет хранить шифротекст и заголовок LUKS на разных устройствах.

Ну и ладненько. Это значит, что теперь у нас может иметься в наличии том данных, забитый случайным мусором, причём совершенно без всяких осмысленных сигнатур. Описание этой опции содержит несколько больше информации, предостережений и предупреждений, однако в сухом остатке это всё, что требуется. И тем не менее, я настоятельно рекомендую прочитать это отличное руководство.

Ещё одна весьма полезная опция — это --align-payload, которая позволяет расположить настоящие данные по определённому смещению относительно начала тома:

--align-payload <число 512-байтных секторов>
 

Выровнять начало контейнера по границе данного числа 512-байтных секторов. Эта опция используется с luksFormat.

Если не указана, то для расчёта оптимального выравнивания cryptsetup попытается использовать топологию нижележащего устройства, предоставленную ядром. Если такой возможности нет (или рассчитанное значение является кратным значению по умолчанию), то по умолчанию данные выравниваются по границе 1MiB (то есть, 2048 512-байтных секторов).

Если заголовок LUKS отделён от данных, эта опция указывает смещение на устройстве данных. См. также опцию --header.

И это тоже классно, потому что теперь мы свободно можем сдвигать наши данные в любую часть тома. Идею улавливаете, да?

Вкратце:

  1. Инициализируем том для шифрования: полностью перезаписываем его случайными данными.
  2. Делаем «официальный» зашифрованный том и скидываем на него немножко заражённого вареза, спираченного музла, прона полезных свободных программ, записей вашей любительской рок-группы, фильмов про любовь и т.п., в общем, того, за что вам дадут не больше двух лет условно.
  3. Используя указанные выше эзотерические опции cryptsetup'а, создаём скрытый том (внутри «официального») и выносим его заголовок на внешний носитель. Здесь вы можете хранить по-настоящему опасную информацию (типа ваших детсадовских фоток или планов по завоеванию мира).

Собственно, народ, это всё. Никакой магии. Естественно, нельзя забивать «официальный» шифрованный диск под завязку по той простой причине, что часть его пространства отдана под скрытый контейнер. И, как я уже сказал в начале, вы можете, если хотите, создать несколько скрытых дисков, следуя той же логике.

Вот… А если вам всё же нужны подробности, то специально для вас —

Пошаговое руководство

Внимание!

Следующие ниже команды приведут к уничтожению ваших данных, если выполнить их, не включая мозги. Утерянную информацию невозможно будет восстановить, поскольку утилиты типа dd работают на низком уровне (то есть, ниже уровня файловой системы). Поэтому невозможно будет откатить изменения или отменить их действие, даже если вы прервёте выполнение сразу же после запуска.

Короче, не делайте этого, если не можете придумать осмысленного объяснения тому, как каждый шаг соотносится с вашими целями. И сделайте бэкап. Сейчас же.

Итак, предположим, у нас есть некое устройство с несколькими разделами. Пусть это будет, например, /dev/sdb. И пусть /dev/sdb1 будет относительно небольшим (8ГБ) разделом, предназначенным для шифрования. Мы разделим его 5 к 3, где 5-гиговая часть будет «официальной», а 3-гиговая — скрытой. Положим также, что ключ для зашифрованного диска мы будем держать в /etc/keys, а заголовок скрытого контейнера, соответственно, на внешнем USB-накопителе, который смонтируем в /media/user/ExtUSBStick. Я полагаю, вы уже в курсе, какие разрешения нужно выставить на хранилище ключей, как настроить encfs/ecryptfs для безопасного хранения конфиденциальных данных на небезопасных устройствах, а также о том, что реальные секретные ключи имеет смысл скопировать и хранить в нескольких территориально разделённых сейфах.

Вот и ладушки, завязываю бурчать и перехожу к сути вопроса.

  1. Инициализация устройства /dev/sdb1:

    dd if=/dev/urandom of=/dev/sdb1 bs=16M
    
  2. Делаем ключ для шифрованного тома. 512 битов (64 байтов) для наших целей выше крыши:

    dd if=/dev/urandom bs=64 count=1 >/etc/keys/secret.key 2>/dev/null
    
  3. Шифруем том, используя только что созданный ключик:

    cryptsetup luksFormat /dev/sdb1 /etc/keys/secret.key
    
  4. Открываем шифрованное устройство и настраиваем маппинг в secretdata:

    cryptsetup luksOpen --key-file /etc/keys/secret.key \
    /dev/sdb1 secretdata
    
  5. Создаём на зашифрованном томе файловую систему (напр., btrfs):

    mkfs.btrfs -L SecretData /dev/mapper/secretdata
    
  6. … и монтирум её:

    mount /dev/mapper/secretdata /var/secretdata/
    
  7. Памятуя о 5-гиговом ограничении, устанавливае квоту для подтомов:

    btrfs quota enable /var/secretdata/
    
  8. Поскольку квоты btrfs действуют только для подтомов, давайте создадим одну такую штуку:

    brfs subvolume create /var/secretdata/workingvolume
    
  9. … и применим к нему указанную квоту (обратите внимание, что подтома btrfs могут быть смонтированы как обычные файловые системы, так что, возможно, впоследствии вам будет удобнеее монтировать именно этот подтом вместо всей фс):

    btrfs qgroup limit 5G /var/secretdata/workingvolume
    
  10. Заполняем его какими-то данными:

    debootstrap --variant=buildd testing /var/secretdata/workingvolume
    
  11. Ну и всё, теперь об этой части можно забыть:

    umount /var/secretdata
    cryptsetup luksClose secretdata
    
  12. Сейчас создадим «рыбу» для заголовка и напихаем в неё случайного мусора:

    dd if=/dev/urandom of=/media/user/ExtUSBStick/hidden.head bs=4M count=1
    
  13. А вот теперь наступает тот самый момент, когда начинается настоящая магия. (Что? Я сказал, что никакой магии нет? Значит я наврал.) Мы используем тот же самый секретный ключ, однако, не целиком, а только половину (со смещения в 32 байта). Тем не менее, оставшиеся 256 случайных бит вполне способны стать хорошим ключом. Затем мы отделим заголовок и положим его на флэшку. И наконец, мы скажем cryptsetup'у, что хотим сместить наш скрытый контейнер на 5ГБ (т.е. на 10485760 512-байтных блоков) относительно начала тома:

    cryptsetup --keyfile-offset 32 --header /media/user/ExtUSBStick/hidden.head \
    --align-payload 10485760 luksFormat /dev/sdb1 /etc/keys/secret.key
    
  14. Да-да, всё настолько просто. Теперь откроем новое зашифрованное устройство:

    cryptsetup luksOpen --key-file /etc/keys/secret.key --keyfile-offset 32 \
    --header /media/user/ExtUSBStick/hidden.head /dev/sdb1 realsecretdata
    
  15. Накатим любую фс, какую захотим:

    mkfs.btrfs /dev/mapper/realsecretdata
    

Ну и так далее…

Полезные ссылки

Для тех, кто хочет знать несколько больше, вот некоторое количество дополнительных источников информации:

А теперь, как выразился автор cryptsetup'а, «если вы настаиваете на необходимости выстрелить себе в ногу, то вы уже имеете представление о том, как это можно сделать». Удачи!