Шифрование отдельных файлов с помощью cryptsetup/LUKS



Разобрался, как шифровать отдельные файлы с помощью openssl:



(Если есть ошибки, прошу указать.)

Просьба подсказать, как подобное осущеcтвить с помощью cryptsetup или LUKS. Интересует не столько бессигнатурность, сколько простота действий. Конкретно, хотелось бы шифровать по паролю без использования асимметрики. Многократное чтение man cryptsetup и гугление, в том числе на pgpru.com, не помогли.

Комментарии
Гость (05/04/2015 20:10)   
cryptsetup не для файлового, а полнодискового шифрования, поэтому вряд ли это хорошая идея. Но в принципе можно если с файлом связать блочное устройство



Появляется шированное устройство /dev/mapper/name, на которое можно записывать например поблочно командой dd. Наверное проще создать на нём файловую систему, примонтировать её и записать файл стандартным способом



По завершении работы все действия произвести в обратном порядке



Команды не проверял, но скорей всего должно работать, т.к. ранее воспроизводил это неоднократно.
— unknown (05/04/2015 20:38)   
Когда-то делал такое. В поднятый на losetup файл можно через cat загнать файл-архив. Из-за некорректной обрезки последнего блока будут ошибки, но его можно оттуда извлечь обратно: в конце несжатого tar-архива большой блок, который устойчив к этому. Но это трюкачество. Раньше ещё был aes-pipe, совместимый с loop-aes, вот там такое можно было делать штатно. Но сейчас loop-aes устарел и не используется.
Гость (05/04/2015 20:47)   
Думаю что на VPS такой способ может оказаться полезным. Т.к. виртуальный диск на разделы не разбить, можно создать шифрованную ФС в файле, примонтировать и разместить на ней некоторые данные. Например исполняемые файлы, конфигурационные, базы данных. При физическом доступе можно наверное расшифровать, сняв дамп памяти. Но если об этом заранее не позаботиться, то после изьятия сервера форензиков будет ждать сюрприз.
— unknown (05/04/2015 20:50)   

Процедура изъятия VPS — это нечто интересное само по себе.
Гость (07/04/2015 08:43)   

Спасибо за корректную простановку ссылки, это облегчило поиск. Как вы, наверное, знаете, там в комменте идёт отсылка к этому примеру[link2]. Обратите внимание, что для бессигнатурности там используются трюки. Кроме того, там есть кое-какие предостережения в плане IV (неохота вспоминать) и KDF для шифрования (KDF вроде как нет вообще). Если честно, шифровать файлы openssl'ем — это коряво ввиду озвученных косяков. Если бы лично мне позарез понадобилось бессигнатурно зашифровать файл, я бы воспользовался plain mode cryptsetup (как ФС на файле или непосредственно), а если просто зашифровать, то GnuPG.


Это не является штатной опцией cryptsetup, но из имеющихся опций неявно следует, что так можно сделать. Гугление могло бы помочь, только если какой-то гуру выложил бы рецепт. В общем, это пример как раз достойного вопроса для уровня pgpru.


Можно сделать и пофайлово, но это только для извращенцев и через скриптомесево.


Не нужно. Файл может передаваться как аргумент напрямую cryptsetup'у, он сам из него сделает блочное устройство.


+1. Это будет работать быстро, штатно и везде, в отличие от пофайлового шифрования. К тому же, так можно легко добавлять туда и несколько файлов (хотя если процедура заточена под один конкретный, то всегда можно предварительно создать архив).


Это не трюкачество, а дебилизм с фатальным непониманием матчасти. Блочные устройства, в отличие от файлов, не даунскейлятся с секторов на байты. Если из файла сделать LUKS-устройство, то его отмапленная часть будет обрезана до целого числа секторов. Как туда запихать файл? Либо в конце будет свободное место, либо файл обрежется, и как его потом оттуда извлекать? Получается костыльно, но придётся писать и файл и его размер и ещё учесть округление до секторов. Показываю мастер-класс. Оно работает, причём правильно (сравнивал по хэшам шифруемого и расшифрованного файлов). Я проверял.

Скриптомесево №3


Скрипт шифрования luks_encrypt.sh:
#!/bin/sh
set -x 
 
# Шифруемый файл (могут быть проблемы с именами файлов,
# содержащими пробелы и спецсимволы):
File=$1
# Его размер в байтах:
FileByteSize=`cat "$File" |wc -c`
# Его размер в секторах (будет на один сектор
# больше, если его размер равен целому числу
# секторов -- неохота это фиксить):
FileSectSize=$(( $FileByteSize / 512 + 1 ))
 
# Именем зашифрованного файла будет:
FileEnc="$1.enc"
# Размер файла в байтах дополним размером заголовка LUKS.
# Расшифрованное устройство будет обрезано до целого числа
# секторов. Мы фиксим это и закладываем лишний сектор
# для записи размера файла:
FileEncSectSize=$(( 4096 + $FileSectSize + 1 ))
 
# Создадим файл нужного размера (для больших файлов
# лучше покурить способ с sparse, чтобы файл писался
# лишь единожды, а не 2 раза как сейчас: заполняясь нулями
# и потом шифрованными данными):
dd if=/dev/zero of="$FileEnc" count=$FileEncSectSize
 
cryptsetup_options="-q -c aes-xts-plain64 -s 512 -h sha512"
 
# Открываем LUKS-контейнер на зашифровываемом файле:
cryptsetup $cryptsetup_options luksFormat "$FileEnc"
# Имя временного устройства делаем случайным:
DeviceName=`tr -dc "[:alpha:]" < /dev/urandom | head -c 6`
cryptsetup luksOpen "$FileEnc" $DeviceName
 
# Затираем нулями тот сектор, который будет содержать
# размер файла:
dd if=/dev/zero of=/dev/mapper/$DeviceName count=1
# Записываем в него сам размер файла:
echo $FileByteSize | dd of=/dev/mapper/$DeviceName 
 
# Записываем шифруемый файл в LUKS-контейнер:
dd if="$File" of=/dev/mapper/$DeviceName seek=1
 
cryptsetup luksClose $DeviceName
 
sync
Скрипт расшифрования luks_decrypt.sh:
#!/bin/sh
set -x 
 
# Расшифровываемый файл:
File=$1
# Именем расшифрованного файла будет:
FileDec="$1.out"
 
# Имя временного устройства делаем случайным:
DeviceName=`tr -dc "[:alpha:]" < /dev/urandom | head -c 6`
 
cryptsetup luksOpen $File $DeviceName
 
# Считываем размер файла в байтах
FileByteSize=`dd if=/dev/mapper/$DeviceName count=1 2>/dev/null | strings`
 
# Записываем расшифровываемый файл (способ очень медленный и плохо
# работает на больших файлах; я не раскурил, как сделать то же самое
# более оптимальными опциями dd, чем с побайтовой записью):
dd if=/dev/mapper/$DeviceName of=$FileDec bs=1 skip=512 count=$FileByteSize
 
cryptsetup luksClose $DeviceName
 
sync
Для бессигнатурки можно сделать аналогично.

Как это работает


Зашифровать файл:
# ./luks_encrypt.sh filename
(дважды спросится пароль; работает, естественно, только под root'ом). Расшифровать:
# ./luks_decrypt.sh filename
Подводных камней в этом способе много. Например, в старых LUKS размер хидера был 4040 секторов, теперь вот он иной. Кто-то даже писал, кажется, что размер хидера вообще не фиксирован стандартом, но его можно посмотреть через luksDump (опция payload). У меня он 4096, например. Поначалу долго мучился и не мог понять, почему с 4040 не работает, и cryptsetup пишет про нарушение оффсета. В общем, надо быть морально готовым к тому, что на другой системе с другой версией cryptsetup это может однажды не расшифроваться.
— SATtva (07/04/2015 08:55)   

Равно, как и на той же системе после очередного обновления.
Гость (07/04/2015 09:46)   
Не, ну вручную всё это можно будет разгрести, в любом случае. Просто лишняя работа будет. Если глубоко рыть, то при обновлении cryptsetup'а и что-то полностью штатное потенциально может слететь.

У меня в памяти отложился инцидент с mcrypt. Я ради бессигнатурности раньше им шифровал соль (опция -b). Потом я поставил другую ОС, где была другая версия mcrypt, и всё. Старые файлы расшифровываться перестали. Хорошо, у меня был доступ к предыдущей ОС'и, поэтому я смог перешифровать те файлы, но вообще пример показательный.
Гость (07/04/2015 19:22)   

Хотелось поберечь нервы разметка-куну[link3]. Это Вам спасибо, что заметили, и за очередную порцию "информации к размышлению".

Благодарю всех за ответы. И вдруг, и неожиданно вопрос оказался, как всегда, совсем-совсем непростым. :-)
Гость (08/04/2015 02:11)   
   Дело не в способе простановки ссылки, а в самом факте её простановки. Кстати, по смыслу в данном треде эта цитата (OP) «внешняя», поэтому там должен быть не знак больше, а <[текст]>.


   Можно было бы в стиле unknown-SATtva указать на общие факты, которых достаточно для написания готового скрипта, если знать матчасть, но, конечно, готовый инструмент — это готовый инструмент, а не заметки на коленке. Мне вот матчасть пришлось доизучить на ходу, потому что изначально не было очевидно, что любое блочное устройство состоит из секторов блоков (слегка тавтологично, но, тем не менее), и их нецелое число там не сделать никак. Кстати, размер сектора/блока на разных системах может быть разным, но я отличного от 512 не видел (может быть, где-то ещё 128 или 256 было?).
   Ещё одна тонкость — извраты с dd. Здесь они не так сильно вылазят, потому что идёт запись в блочное устройство, размер которого не может быть изменён, но вот если бы запись делалась в файл, всё было бы тоньше. Наверно, тем, кто с этим работал, это покажется тривиальным, но вообще логика там не такая очевидная. Например, при dd в файл с seek=X будет автоматически создано X блоков нулей, а потом в конец добавлен контент. Если запись таким образом идёт в середину файла, всё до середины будет оставлено, как есть, после середины добавлен контент, а оставшаяся часть будет (сюрприз!) обрезана. Т.е. как по уму записывать фиксированный набор байтов в фикисрованное место файла, ничего не обрезая, — для меня осталось вопросом (который в некоторых частных случаях решается теми или иными хаками, но, наверно, можно и проще).
   Ещё одна тонкость была — как записать и считать размер файла. Можно было бы сделать сложнее и оптимальней: не тратить на это лишний сектор, а вычислять необходимое минимаьное число секторов для записи и файла и его «заголовка», где потом распознавать, где файл, а где заголовок, по определённым меткам. Впрочем, раз 4096 секторов и так уже расходуется чисто под заголовок LUKS, будет там на один сектор больше или меньше — уже не важно (для бессигнатурки, не отягощаемой LUKS-заголовком, это имело бы больше смысла).
   При считывании размера файла через dd формально пишется на вывод терминала всё хорошо, но с точки зрения внутренностей шелл не считает это цифрами, потому что там нули. И, кстати, очень хорошо, что там нулевые байты — это не ноль в смысле цифры в десятичной системе, а то было бы совсем весело. :-) В общем, хак со strings как-то решает эту проблему, вырезая нужное, но я не уверен, что именно так делается считывание ASCII-символов из файлов в скриптах. Хотелось бы почитать что-то грамотное на тему, как писать в файлы и читать из них, а не переизобретать велосипеды на коленке.


   Хотелось бы, чтоб кто-нибудь подсказал. Такое впечатление, что dd читает и пишет блоками, причём количество считанного и записанного должно быть кратно размеру блока. Более того, оффсеты в читаемом и записываемом тоже задаются кратными размеру блоков, тут же надо сделать отступ 512, который не кратен размеру файла. Просто записать произвольный размер — это bs=размер count=1 (не знаю, как это будет работать на больших файлах). Я пытался сделать с seek_bytes=1 и skip_bytes=1, но на вторую опцию dd начал почему-то жаловаться. Понятно, что можно из одного dd сделать несколько и решить эти проблемы, но хотелось бы это записывать покороче и без усложнения логики. В текущем скрипте при расшифровании запись всего 200KB/s. Это очень медленно, но для небольших текстовых файлов сойдёт.
   Наконец, замечание общего характера: на мой взгляд, не нужно. Во-первых, это требует скрипт, который надо где-то хранить (хотя его смысл прост, можно и руками извлекать, если это бывает нужным очень редко). Во-вторых, единственное применение, где это могло бы быть осмысленным — удалённые бэкапы, но бэкапится обычно не один файл, а много. Раз их много, проще оценить минимальный размер необходимой ФС и сделать всё штатно через ФС на файле[link4]. Впрочем, одно из применений всё же имеется, но там нужен именно бессигнатурный вариант — это пересылка файлов через файлообменники и другие недоверенные сервисы, где не хочется светить информацию о том, чем были зашифрованы файлы, и вообще, мусор это или шифрованные данные.
— unknown (08/04/2015 09:55)   

Для CD/DVD вроде как 4096.


dd bs=1c — размер блока в один байт.



Есть ещё опасение насчёт криптостойкости. Если делать tar -c -f- /[path]/* | gpg -c > file.tar.gpg, то у нас всё точно корректно зашифруется: будет правильная обработка пароля, уникальный (случайный, каждый раз разный) вектор инициализации для всего файла, даже если шифровать несколько раз одно и тоже одинаковым паролем и давать копии этого противнику и т.д. А при нестандартном использовании cryptsetup можно напортачить и незаметить этого.
Гость (08/04/2015 10:51)   

Там так и стоит:
dd if=/dev/mapper/$DeviceName of=$FileDec bs=1 skip=512 count=$FileByteSize
(c можно опустить). Дело в том, что читать и писать по одному байту — это очень медленно.


Вы имеете в виду, что режим поблочного шифрования не такой же хороший, как в GnuPG? Было предостережение на предмет того, чтобы не давать противнику видеть шифртекст контейнера с разным его содержимым (в разное время) [атака уборщицы]. Тут, правда, контейнер одноразовый, поэтому в лоб такого не будет происходить, но мало ли...

Хуже, если шифрование будет бессигнатурным. Там пароль один и несменяемый.

--skip, -p <number of 512 byte sectors>

Start offset used in IV calculation in 512-byte sectors (how many sectors of the encrypted data to skip at the beginning). This option is only relevant for the open action with plain or loopaes device types.

Hence, if --offset n, and --skip s, sector n (the first sector of encrypted device) will get a sector number of s for the IV calculation.

© man cryptsetup ← лично мне непонятна вот эта магия. Откуда в норме берётся IV в plain mode? А в LUKS? Нужно ли под IV выделять отдельный сектор? И т.д.
— unknown (08/04/2015 11:10, исправлен 08/04/2015 11:15)   

В GnuPG — достаточно хороший режим и протокол для файлового шифрования, в dmcrypt — достаточно хороший для шифрования ФС. Использовать режимы GnuPG для ФС — грозит однозначным фэйлом в ряде ситуаций. А можно ли использовать режимы dmcrypt для файлов? Можно долго разбирать теорию, но проще решить, что лучше так не делать.



Статическая псевдорэндомизация, синтетический IV: IV = Hash(номер сектора ║ ключ ║ содержимое предыдущего сектора ║ что-то ещё, могут быть варианты). Это примерно так в ESSIV. Любителям придираться: формула от балды, пироги с сапогами и всё-такое. Использовать только для иллюстрации принципа. В XTS всё ещё сложнее.

Гость (08/04/2015 12:18)   

Если ФС на файле, и эта ФС не меняется без полного пересоздания всего и вся, то чем плохо? Я не вижу причин.


Думаю, можно. Шифрование ФС влечёт за собой более жёсткие требования, чем шифрование файлов, потому что, как вы говорили, ФС целиком не перешифровывается при изменении содержимого некоторых секторов. Но в случае вышеприведённого скрипта всё это и не нужно: генерируется ключ, записывается в LUKS-слоты, этим ключом шифруется содержимое блочного устройства (куда записан файл); содержимое блочного устройства после этого никогда не меняется. Если в этой схеме есть уязвимость, то она, тем более, есть и при шифровании ФС. Я не вижу, чем этот случай отличается от случая «отдал противнику свой диск, шифрованный LUKS'ом».


Я не про то, как это внутренне устроено, а про примитивное юзерское. Если по простому: в каких случах нужно указывать --skip, и какой в этом будет смысл? Могли бы вы привести наглядные примеры? Во всех случаях (бессигнатурка, бессигнатурка с оффсетом (шифруем неразмеченное дисковое пространство начиная с какого-то сектора)] я пока что нигде эту опцию не использовал. Это правильно? Где она может быть нужна?
Гость (08/04/2015 13:04)   

А, Вы об этом. :-) Этим я пытаюсь проявить элементарную вежливость в общении. Увидел, что другие так делают, и тоже так поступаю. Без таких ссылок читатель/отвечающий будет тратить лишнее время.
Гость (08/04/2015 21:29)   
Обратите внимание, что для бессигнатурности там используются трюки

Бессигнатурно шифровать openssl можно без трюков



IV создаётся на основе пароля, но можно указать опцией -iv, тогда при расшифровке его необходимо помнить. Удобно также шифровать mcrypt



Плюс в том, что IV генерится из рандома и записывается перед шифртекстом, поэтому помнить не нужно. Тоже убирается опцией noiv, тогда будет создаваться из пароля, как в openssl. Другой плюс это 256-битный блок Rijndael, в отличие от 128-битного в openssl, а также больше выбор алгоритмов, включая Twofish и Serpent.

Если запись таким образом идёт в середину файла, всё до середины будет оставлено, как есть, после середины добавлен контент, а оставшаяся часть будет (сюрприз!) обрезана.

Если файл примонтирован как устройство, то при записи в середину он не может обрезаться. Кстати, забыл написать в comment91420[link4], что перед связыванием файла с блочным устройством, его нужно чем-нибудь заполнить до нужного размера, если он пустой. Например для 10 мегабайт



Откуда в норме берётся IV в plain mode?

IV-соль в plain не используется, т.к. пароль не шифруется, а преобразуется в ключ хешированием или испольуется напрямую (aes-plain). При использовании LUKS IV для шифрования ключа паролем берётся из /dev/urandom по умолчанию (можно изменить опцией --use-random) и сохраняется в заголовке. Для шифрования блоков диска IV со стороны вообще не используется, а генерится из ключа по алгоритму ESSIV (как unknown показал).
Гость (09/04/2015 03:35)   

А там по ссылке трюки как раз для того и используются, что и соль есть, и помнить ничего не надо. Более того, ваш пример, судя по комментарию unknown'а[link5] крайне не рекомендуется к использованию (также см. /comment39340[link6]). Там же объяснено, почему вот так:

Тоже убирается опцией noiv, тогда будет создаваться из пароля, как в openssl.

делать не надо. И, кстати, вот ещё[link7] комментарий в тему этого обсуждения.


openssl вообще не умеет AES-256? Тут[link2] aes-256-cbc указано опцией.


Вот именно поэтому там сказана оговорка:

Ещё одна тонкость — извраты с dd. Здесь они не так сильно вылазят, потому что идёт запись в блочное устройство, размер которого не может быть изменён, но вот если бы запись делалась в файл, всё было бы тоньше.

Я поначалу ошибочно подумал, что шифрованный файл надо собирать из кусков. В этом случае эта проблема бы вылезла.


Всё хуже. Поидее надо заполнять не нулями, а рандомом (уж во всяком случае в вашем примере — точно). В моём примере, может быть, это будет избыточным, но это надо анализировать. Если шифрование поблочное/посекторное, а размер устройства в точности совпадает с заполняемым, то неизменяемых блоков/секторов не будет. Правда, если размер файла равен целому числу блоков, то в приведённом скрипте в последний сектор ничего так и не будет записано, а это уже какая-никакая дополнительная информация о размере файла. В общем, похоже, если всё так, то надо либо для гарантии тоже забивать всё рандомом[link8], либо фиксить последний сектор.


Start offset used in IV calculation in 512-byte sectors (how many sectors of the encrypted data to skip at the beginning). This option is only relevant for the open action with plain or loopaes device types.

Тогда зачем (см. эту цитату выше) в man cryptsetup это написано?

Плюсы и минусы mcrypt



Помимо замечания в /comment91478[link9] у меня сложилось впечатление, что с mcrypt всё не очень хорошо, не очень надёжно, а его использование не очень рекомендуется. Возможно, всё эти представления ошибочны, когда идёт речь именно о бессигнатурном шифровании, но всё же. Сейчас прогуглил все его упоминания за время существования форума, и вот такая картина получается:

О[link10]трезался хидер при симметричном шифровании с паролем и программа без каких-либо специальных распознавателей всё равно этот факт определяла по типу ошибок при попытках расшифрования.

Это касается любого симметричного пофайлового шифрования? И openssl и mcrypt? Если так, в чём концептуальное отличие, приводящее к нераспознаваемости контейнеров TC? Non-malleability? Кто мешает таким же образом шифровать и файлы? Это было бы менее безопасным? Почему файлы шифруются не точно так же?

Э[link11]то касается любого симметричного пофайлового шифрования?

Нет, только особенностей его реализаций.

И openssl и mcrypt?

Я не знаю, что они пихают в шифртекст, кроме простых заголовков.

Е[link12]сли кому-то нужен именно криптографический конструктор, а не полноценная рабочая криптосистема, то больше для этого подходит mcrypt.

Ой! А я его для серьёзных вещей юзаю с опциями типа m(de)crypt -b... unknown советовал. Разве это ещё "экспериментальный" продукт?!

Об этом речи нет. Это программа для тех, что знает, что делает. Ближе к криптобиблиотеке. То есть определённо не для среднестатистического пользователя средств шифрования.

Собственно в качестве криптобиблиотеки в некоторых программах и применяется libmcrypt.

Хотя это не такой стандарт де-факто, как openssl, который при разработке приложений стараются использовать в первую очередь.

В[link5] mcrypt опция bare по крайней мере что-то гарантирует хотя бы со слов документации. И всё равно, нужно разбираться, прежде чем например это куда-то встраивать

Т.е. вопрос в том, что лучше для бессигнатурности: создать контейнер в plain mode или использовать mcrypt? Мне первый вариант интуитивно кажется более доверяемым, т.к. это всё-таки стандартный и всюду используемый cryptsetup, написанный со знанием дела.
— SATtva (09/04/2015 08:09)   

AES != Rijndael. У первого размер блока (не ключа) строго равен 128 битам, у второго есть вариант со 128- и 256-битовым блоком.
Гость (09/04/2015 09:33)   
openssl вообще не умеет AES-256? Тут aes-256-cbc указано опцией

В AES-256 размер блока 128 бит, как тут уже ответили.

>Start offset used in IV calculation in 512-byte sectors (how many sectors of the encrypted data to skip at the beginning). This option is only relevant for the open action with plain or loopaes device types.

Тогда зачем (см. эту цитату выше) в man cryptsetup это написано?

Наверно для именения нумерации блоков, используемой ESSIV при генерации IV. В plain mode (без заголовка) пароль не шифруется, поэтому соль не нужна.

Т.е. вопрос в том, что лучше для бессигнатурности: создать контейнер в plain mode или использовать mcrypt?

На мой взгляд для шифрования одного файла лучше mcrypt, чем велосипеды с cryptsetup. Лично для меня проще стандартное действие – скачать и скомпилировать программу, чем возиться со скриптами. Если шифруется бэкап c ФС, тогда удобнее cryptsetup. По большому счёту особой разницы нет.
Гость (10/04/2015 14:24)   

Так зачем пользователям cryptsetup лезть в эти тонкости криптографии? Где и зачем это может быть нужно? Может быть, Unknown опцию --skip прокомментирует? В man'е я вижу только это:

If the original device used an offset and but did not use it in IV sector calculations, you have to explicitly use --skip 0 in addition to the offset parameter.

Когда реализуется случай «did not use it in IV sector calculations»?
— unknown (10/04/2015 14:38, исправлен 10/04/2015 14:39)   

Так подробно же про skip написано:

--skip, -p
how many sectors of the encrypted data to skip at the beginning. This is different from the --offset options with respect to IV calculations. Using --offset will shift the IV calculation by the same negative amount. Hence, if --offset n, sector n will be the first sector on the mapping with IV 0. Using -""-skip would have resulted in sector n being the first sector also, but with IV n. This option is only relevant for create action.
Гость (10/04/2015 15:10)   
В моей версии cryptsetup'а это пояснение уже убрали.

Для начала, я не знаю, что такое вектор инициализации, и чему равен его размер. Для меня, как для простого юзера, это просто внутренний параметр для шифра, который всегда как-то вычисляется автоматически и правильно. Почему вдруг в какой-то момент я должен выяснять, как он вычисляется — уже само по себе большой вопрос.


Почему negative-то? Если речь о сдвиге сектора, который будет использоваться для вычисления IV, то сдвиг как раз positive. И как из содержимого сектора вычисляется IV?


Нетривиально. Ключ вычисляется из пассфразы. Offset — это просто начиная с какого сектор блочного устройства его отмаппить в шифрованное. Как отсюда следует, что IV оказывается равным нулю?

Вроде IV=0 — это плохо. И как тогда надо делать, когда шифрование происходит не с начала устройства? Надо каждый раз писать --offset n --skip n? А когда эти параметры стоит делать разными? Или лучше делать --offset $((n+1)) --skip n? Я ничего не понял.
— unknown (10/04/2015 15:48, исправлен 10/04/2015 15:52)   

Это параметр режима шифрования, а не шифра.



До тех пор пока вы не хотите странного. Если хотите — то можете простреливать себе ногу. Вам дана такая возможность. В случае с крипто и отрицаемостью — такое самопростреливание ещё и незаметно до поры до времени, внешне всё работать будет.



Смотря для чего.


Если вы — простой юзер и не понимаете в векторах и режимах, то не пытайтесь сделать нечто нештатное. Пока не изобрели стандартизированный и внедрённый в доверяемые утилиты протокол бессигнатурного шифрования из коробки, то не пытайтесь нагородить его самопальными костылями.

Гость (10/04/2015 16:12)   

Бессигнатурное шифрование достигается добавлением пары опций, ничего сильно нестандартного тут нет. То, что вы лично и для себя считаете это ненужным — это ваши личные проблемы.


Для cryptsetup, где устройство шифруется не с первого сектора. Здесь[link13] в четвёртом и седьмом пунктах оффсет указан, а скип нет. Это правильно или надо фиксить?
— unknown (10/04/2015 16:18)   

Всецело с этим согласен.


Так это надо подумать над тем, что я считаю ненужным. И много чего написать, где это может вылезти. Попытка эмулировать скрытые разделы со смещение — первое, что приходит в голову. Я ограничиваюсь только недоказанным предупреждением, что здесь может возникнуть проблема.
Гость (10/04/2015 16:47)   

Будьте добры, что означает "эмулировать стрытый раздел со смещением"? Понятен смысл выражения "создать", но не понятен "эмулировать".
— unknown (10/04/2015 16:54, исправлен 10/04/2015 16:55)   

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

Гость (10/04/2015 17:05)   
Спасибо
Гость (10/04/2015 19:32)   
Возможно ещё применение когда устройство разбито на разделы, а шифруется не первый раздел. Тогда опция skip позволяет в дальнейшем присоединить к шифрованному пространству предыдущие разделы и расширить файловую систему без перешифровки расширяемого раздела.

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

1. Уметь установить программу (mcrypt или cryptsetup)
2. Помнить режим шифрования (для бессигнатурного варианта).
3. Помнить пароль

После расшифровки и доступа к скриптам можно уже получить доступ к устройствам, зашифрованным экзотическими способами (со сдвигом блоков и т.п.)
— unknown (10/04/2015 20:43)   

Насчёт mcrypt не скажу, а для cryptsetup скачиваете любой инсталляционный образ любого Linux'a, в котором можно что-то запускать с флэшки в rescue-режиме, криптсетапите и монтируете, что нужно. Cryptsetup и GnupG — штуки штатные, на них столько всего завязано, что они уже никуда не денутся.


На данный момент оптимальнее так:

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

Use --offset to specify device offset. Note that the units need to be specified in number of 512 byte sectors.

Use --skip to specify the IV offset. If the original device used an offset and but did not use it in IV sector calculations, you have to explicitly use -""-skip 0 in addition to the offset parameter.


Как-то стрёмно использовать cryptsetup c офсетами после таких пояснений. Я не удивлюсь, если там внутри критично напортачили, а в случае обнаружения баги скажут, что это опции неприоритетные, за них никто не ручался.
Гость (10/04/2015 21:31)   

Разве эта опция — не такая простая вещь для владеющих темой?


А в обычном plain mode без смещения (-c aes-xts-plain64 -s 512 -h sha512) не может возникнуть? Чем это отличается от:
  1. С помощью dmsetup отмаппливаем сектора с n'ого до последнего.
  2. К отмаппленному устройству применяем обычный cryptsetup (plain mode) без всяких смещений, т.е. без --skip и без --offset
Ы? По-моему, это совершенно эквивалентно. Если всё так плохо и непросто, как вы описываете, то поидее проблема должна в любом plain mode вылезать.


Наверно, не предыдущие, а последующие.


Вы проверяли? Это работает? Я вам уже написал, что здесь /dev/mapper лишнее.


(проблема выеденого яйца не стоит)


(вообще непонятно, что они там хотели этим сказать)

Простите, на какую из этих двух ваших реплик теперь ориентироваться?
Гость (12/05/2015 17:33, исправлен 16/05/2015 20:31)   

offset эквивалентен dmsetup linear. Это можно проверить экспериментально:

# cryptsetup <опции> -o оффсет create zz /dev/sda
равносилен
# dmsetup create yy --table '0 размер linear /dev/sda оффсет'
# cryptsetup <опции> create zz /dev/mapper/yy
При задании только --offset IV отсчитывается, как если бы начальный сектор криптораздела был нулевым (это следует из аналогии с dmsetup linear). То есть, можно потом перенести криптораздел на любой другой оффсет, и при задании правильной опции --offset IV будет тем же.


--skip, как я понял, нужен при создании «частичных» крипторазделов. Допустим, нужно адресовать часть криптораздела, отступив от его начала на 8 секторов. Пусть сам криптораздел расположен по оффсету S. Если сделаем --offset S+8, у нас будет неправильный IV, поэтому надо делать --offset S+8 --skip 8. Т.е.

# сryptsetup <опции> --offset S --skip P create zz /dev/sda
равносилен
# dmsetup create yy --table '0 размер linear /dev/sda S-P'
# cryptsetup <опции> create xx /dev/mapper/yy
# dmsetup create zz --table '0 размер linear /dev/mapper/xx P'
за исключением того, что промежуточные устройства реально не создаются (проверено экспериментально). Т.е. делаем отступ S-P на исходном девайсе (/dev/sda), потом открываем полученное устройство (xx), а потом на открытом устройстве делаем сдвиг ещё на P, отображая это в девайс zz.


Таким образом, в plain mode не указывать --skip равносильно указанию --skip 0. Можно указывать, если есть сомнения. Задание опции --offset никак не влияет на IV.


UPD: Когда мы skip не задаём (P=0), IV равен «исходному» для сектора S. Смысл указания skip в том, что мы читаем те же самые сектора, что и без skip (это самое нетривиальное!), но с другим IV. Следовательно, нужно сначала сместиться на P секторов «назад» относительно оффсета, образовать криптомаппинг с «исходным» IV, а затем сместиться вперед на те же P секторов. Отсюда сначала S-P, затем P. В итоге получается, что при указании --offset S --skip P криптомаппинг охватывает сектора начиная с S (!), однако, IV устроен так, как будто мы «пропустили» с начала P секторов (отсюда и название «skip»).

Гость (13/05/2015 18:50)   

Спасибо за исследование.
Гость (13/05/2015 19:21, исправлен 16/05/2015 20:34)   

Пожалуйста. Если соотнести эти факты с тем, что unknown писал на предыдущих двух страницах, вырисовывается примерно такая картина:


  1. IV для первого сектора всегда нулевой, это нормально, и так должно быть.
  2. IV для последующих секторов вычисляется из IV (и данных?) предыдущих секторов по некоторому правилу.
  3. В plain mode cryptsetup по умолчанию каждый раз думает, что первый сектор открываемого/расшифровываемого устройства есть первый сектор всего имеющегося зашифрованного устройства, поэтому ставит ему IV=0. В общем-то, по умолчанию почти всегда так и есть, и это правильное поведение (см. пункт 1).
  4. В случае частичного расшифрования уже шифрованного устройства, когда от его начала надо отступить несколько секторов, нужно использовать иной IV, ненулевой (тут не в безопасности проблема, а в том, что иначе расшифруете содержимое диска неправильно). Указание skip (числа пропускаемых секторов от начала шифрованного устройства) даёт возможность cryptsetup'у правильно вычислить IV для первого расшифровываемого сектора (он не первый на устройства, но первый расшифровываемый), а, следовательно (см. пункт 2), и для всех последующих.

Всё это выглядит так, что IV, в любом случае, вычисляется автоматически по заданным правилам, а опция skip лишь корректирует параметры. Судя по man cryptsetup, сам юзер непосредственно вмешаться в выбор IV (к примеру, задать руками) не может вообще (опция skip — это как выбор значения счётчика для заранее предпопределённого правила вычисления IV).


UPD: Когда --skip не указывается, он по умолчанию равен нулю для plain mode. Да, при этом IV получается, как если бы не было никакого оффсета (это легко проверяется экспериментом с dmsetup linear). Вообще, есть некий базовый режим cryptsetup plain, а offset и skip на него накладываются линейными сдвигами до и после. Опция --skip не меняет адресацию секторов, а исключительно расчет IV. Поэтому в LUKS его вообще нет, о чем ман и говорит нам:


This option is only relevant with plain or loop-aes device types.
— pgprubot (06/10/2015 13:35, исправлен 06/10/2015 13:39)   

Вместо тысячи слов, которые всё равно будет едва ли возможно понять, весь смысл одной картинкой:

.
          S
|<----------------->|
 
                   Та часть криптораздела,
                  которую мы хотим отмаппить
                        (расшифровать)
                      ________/\______
|                    /                \           |
|-------------------------------------------------|
|           \______________  _______________/     |
                           \/ 
               Бессигнатурный криптораздел
                      на /dev/sda
 
           |<------>|
                P
 
 \______________________  _______________________/
                        \/
          Всё блочное устройство /dev/sda
И S и P — оффсеты, но S — оффсет расшифровываемого места относительно исходного блочного устройства, а P — относительно начала бессигнатурного раздела на нём. Из этой картинки видно, что, например, если нужно просто зашифровать часть блочного устройства типа /dev/sda с оффсетом, то P можно смело полагать нулю. Точно так же становится понятно, почему по умолчанию (адресация всего пространства) P и S равны нулю. Оффсет P удобен при ручной организации структуры типа LVM, если кому-то вдруг захочется такое сделать.

— pgprubot (07/10/2015 12:22, исправлен 07/10/2015 12:54)   

LUKS — это просто чёрный ящик, на входе которого пассфраза, а на выходе — мастер-ключ. Ничего более в нём нет. Метод, как шифровать блочное устройство, определяется задаваемым шифром и режимом, а откуда взялся мастер-ключ — вывели с LUKS'а, задали вручную или получили в plain mode — не играет никакой роли. По крайней мере, на самом шифртексте это не скажется никак. Показываю PoC — подключение LUKS-тома в plain mode:


Создание LUKS-тома


  1. Форматируем устройство под LUKS:
    # cryptsetup -q -c aes-xts-plain64 -s 512 -h sha512 luksFormat /dev/VG_name/LV_name
    Enter passphrase:
    Ставим паролем qwerty.

  1. Открываем устройство и нарезаем внутри ФС:
    # cryptsetup luksOpen /dev/VG_name/LV_name LV_name_crypt
    Enter passphrase for /dev/VG_name/LV_name:
    # mkfs.ext4 /dev/mapper/LV_name_crypt
  2. Дампим мастер-ключ LUKS'а в файл и закрываем LUKS-устройство:
    # cryptsetup -q --dump-master-key luksDump /dev/VG_name/LV_name > /tmp/luks_dump.txt
    Enter passphrase: 
    # cat /tmp/luks_dump.txt 
    LUKS header information for /dev/VG_name/LV_name
    Cipher name:    aes
    Cipher mode:    xts-plain64
    Payload offset: 4096
    UUID:           xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
    MK bits:        512
    MK dump:        8f 39 52 7b af 9f 08 68 aa ea 1f b0 9e 3e 27 a2 
                    d8 60 89 5a f0 69 75 92 88 98 4e 9c 0c 74 b9 89 
                    5a c9 87 6e ed 84 37 52 d9 51 14 d4 d8 ba 0c 2e 
                    4c 0c ab dd 2b 18 44 0b c7 8c a8 23 3e b9 6f ab
    # cryptsetup luksClose LV_name_crypt

Подключение LUKS-тома в plain mode


  1. Отредактируем /tmp/luks_dump.txt так, чтоб там был только мастер-ключ в следующем формате:
    # cat /tmp/luks_dump.txt 
    8f 39 52 7b af 9f 08 68 aa ea 1f b0 9e 3e 27 a2
    d8 60 89 5a f0 69 75 92 88 98 4e 9c 0c 74 b9 89
    5a c9 87 6e ed 84 37 52 d9 51 14 d4 d8 ba 0c 2e
    4c 0c ab dd 2b 18 44 0b c7 8c a8 23 3e b9 6f ab
  2. Восстновим бинарный мастер ключ по его hex-дампу и проверим результат:
    # cat /tmp/luks_dump.txt |xxd -r -p > /tmp/master_key
    # cat master_key |hexdump -Cv
    00000000  8f 39 52 7b af 9f 08 68  aa ea 1f b0 9e 3e 27 a2  |.9R{...h.....>'.|
    00000010  d8 60 89 5a f0 69 75 92  88 98 4e 9c 0c 74 b9 89  |.`.Z.iu...N..t..|
    00000020  5a c9 87 6e ed 84 37 52  d9 51 14 d4 d8 ba 0c 2e  |Z..n..7R.Q......|
    00000030  4c 0c ab dd 2b 18 44 0b  c7 8c a8 23 3e b9 6f ab  |L...+.D....#>.o.|
    00000040
    Результат, как видим, правильный.

  1. Подключим LUKS-том с помощью бинарного мастер-ключа, указав тот же режим шифрования и размер ключа и не забыв сделать отступ на LUKS-томе, чтобы убрать LUKS-заголовок:
    # cryptsetup -c aes-xts-plain64 -s 512 -d /tmp/master_key \
      -o 4096 plainOpen /dev/VG_name/LV_name LV_name_crypt
  2. Наступает момент истины:
    # mount /dev/mapper/LV_name_crypt /media/mnt
    Вуаля, всё работает, что и требовалось доказать. Понятно, что аналогичным образом можно выборочно расшифровать и любую часть этого LUKS-тома, указав нужный размер -b и оффсеты (-o и -p).

Мораль:


Если где-то в plain mode (а также с оффсетами и режимами) и есть проблемы с шифрованием, то они же есть и в LUKS'е. Нужно отделять мух от котлет: шифрование — только то, что задаётся опцией aes-xts-plain64, всё остальное — метод получения мастер-ключа, он может быть каким угодно. В этом смысле plain mode ничем не более рыжий, чем LUKS. Другое дело, что в plain mode вопрос безопасного хранения мастер-ключа и выбор стойкой пассфразы — полностью ответственность пользователя (в этом действительно легко напартачить, ничего не заметив).

Ссылки
[link1] https://www.pgpru.com/comment75657

[link2] https://www.pgpru.com/comment39520

[link3] https://www.pgpru.com/comment78729

[link4] https://www.pgpru.com/comment91420

[link5] https://www.pgpru.com/comment39331

[link6] https://www.pgpru.com/comment39340

[link7] https://www.pgpru.com/comment29068

[link8] https://www.pgpru.com/comment80362

[link9] https://www.pgpru.com/comment91478

[link10] https://www.pgpru.com/comment65565

[link11] https://www.pgpru.com/comment65583

[link12] https://www.pgpru.com/comment29051

[link13] https://www.pgpru.com/biblioteka/rukovodstva/zaschitadiska/tailsotricaemoehraneniedannyh

[link14] https://www.pgpru.com/comment92645

[link15] https://www.pgpru.com/comment91667

[link16] https://www.pgpru.com/comment91673

[link17] https://www.pgpru.com/comment91686