id: Гость   вход   регистрация
текущее время 13:22 28/03/2024
Автор темы: Гость, тема открыта 01/04/2015 13:22 Печать
Категории: криптография, софт, приватность, симметричное шифрование, отрицаемое шифрование, свободный софт
https://www.pgpru.com/Форум/ПрактическаяБезопасность/ШифрованиеОтдельныхФайловСПомощьюCryptsetupLUKS
создать
просмотр
ссылки

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



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



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


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


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



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



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



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

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

Спасибо за корректную простановку ссылки, это облегчило поиск. Как вы, наверное, знаете, там в комменте идёт отсылка к этому примеру. Обратите внимание, что для бессигнатурности там используются трюки. Кроме того, там есть кое-какие предостережения в плане 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)   профиль/связь   <#>
комментариев: 11558   документов: 1036   редакций: 4118

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

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

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

Благодарю всех за ответы. И вдруг, и неожиданно вопрос оказался, как всегда, совсем-совсем непростым. :-)
— Гость (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. Это очень медленно, но для небольших текстовых файлов сойдёт.
   Наконец, замечание общего характера: на мой взгляд, не нужно. Во-первых, это требует скрипт, который надо где-то хранить (хотя его смысл прост, можно и руками извлекать, если это бывает нужным очень редко). Во-вторых, единственное применение, где это могло бы быть осмысленным — удалённые бэкапы, но бэкапится обычно не один файл, а много. Раз их много, проще оценить минимальный размер необходимой ФС и сделать всё штатно через ФС на файле. Впрочем, одно из применений всё же имеется, но там нужен именно бессигнатурный вариант — это пересылка файлов через файлообменники и другие недоверенные сервисы, где не хочется светить информацию о том, чем были зашифрованы файлы, и вообще, мусор это или шифрованные данные.
— unknown (08/04/2015 09:55)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664

Для 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)   профиль/связь   <#>
комментариев: 9796   документов: 488   редакций: 5664

В 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, что перед связыванием файла с блочным устройством, его нужно чем-нибудь заполнить до нужного размера, если он пустой. Например для 10 мегабайт



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

IV-соль в plain не используется, т.к. пароль не шифруется, а преобразуется в ключ хешированием или испольуется напрямую (aes-plain). При использовании LUKS IV для шифрования ключа паролем берётся из /dev/urandom по умолчанию (можно изменить опцией --use-random) и сохраняется в заголовке. Для шифрования блоков диска IV со стороны вообще не используется, а генерится из ключа по алгоритму ESSIV (как unknown показал).
На страницу: 1, 2, 3 След.
Ваша оценка документа [показать результаты]
-3-2-1 0+1+2+3