Прячем шифрованные диски

от автора

Что такое криптография — все знают: берем что-то секретное, зашифровываем его — и без ключа никто ничего не прочитает.
Но есть минус: если кому-то очень хочется почитать — вас могут вежливо попросить поделиться ключиком, и отказаться может быть очень сложно.

Что такое стеганография — тоже многие знают: берем что-то секретное и прячем его среди обычного, оно как бы на виду, но если не знать где именно искать — найти сложно.
Тут минус в другом — оно не должно выделяться и бросаться в глаза.

Что, если попробовать совместить одно с другим?

Вот например, есть LUKS.
Можно зашифровать диск, или сделать файл-криптоконтейнер.
Но LUKS буквально кричит «я — секретный секрет, взломай меня!». Большой бинарный файл с легко определяемой сигнатурой, даже если заныкать его глубоко в каталогах файловой системы — при желании найти несложно, а найдя — пойти с вопросами к хозяину.

Но Linux — интересная штука, и в нем есть разные инструменты.
Например, все знают что можно подключить файл как блочное устройство — но не обязательно ВЕСЬ файл.
Можно подключить кусок внутри файла — тогда файл внешне не изменится, и даже сигнатуры будет показывать правильные — но внутри него будет что-то другое.

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

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

Логика программы

1 — запрос текста пароля
2 — формирование хеша-ключа
3 — формирование смещений внутри файла на основе введенного ключа, точнее, вторичного хеша, чтобы даже выявленные смещения никак не уменьшали стойкость самого ключа
4 — подключение куска файла в качестве блочного устройства с прозрачным шифрованием
5 — если это новый файл — перезапись его случайными данными, форматирование, монтирование
6 — если это уже созданный ранее файл — монтирование
7 — если он уже был ранее смонтирован — отмонтирование

В качестве файла-контейнера можно взять любой достаточно большой файл, например видеозапись или образ DVD — после подключения он будет частично испорчен, но по прежнему будет определяться как видеозапись или образ диска.
Внутри него не появятся никакие распознаваемые сигнатуры, что усложняет автоматический поиск «скрытых дисков»

Реализация

Делаем bash-скрипт:

#!/bin/bash # #   if [ $EUID -ne 0 ] ; then   exec sudo "$0" "$@" fi  file=$1 dir=$2  cipher="serpent-xts-plain64" sha="sha512sum"  check_file(){   if [ "x$file" != "x" ] && [ -f "$file" ] ; then     file_ok="y"   fi }  check_map(){   loop=$(losetup -j "$file" -O NAME -n | head -1)   if [ "x$loop" != "x" ] ; then     is_mapped="y"   fi }  enter_pass(){   echo -n "Enter password: "   read -s pass1   echo     if [ "x$pass1" = "x" ] ; then     exit 0   fi    key=$(echo -n "$pass1" | $sha | awk '{print $1}')   tmp=$(echo -n "$key" | $sha | awk '{print $1}')  }  check_dir(){   dir_ok="n"   if [ "x$dir" = "x" ] ; then     echo -n "Enter mountpoint: "     read dir   fi   if [ "x$dir" != "x" ] ; then     if [ -d "$dir" ] ; then       dir_ok="y"     else       mkdir "$dir"       if [ -d "$dir" ] ; then         dir_ok="y"       fi     fi   fi }  mount_dir(){   mount /dev/mapper/stegano_$name $dir   if [ $? -eq 0 ]; then     if [ "x$SUDO_USER" != "x" ] ; then       chown $SUDO_USER:$SUDO_USER $dir     fi     mount_ok="y"   fi } remove_map(){  if [ -b "/dev/mapper/stegano_$name" ] ; then     dmsetup remove stegano_$name     if [ $? -ne 0 ] ; then       echo "ERROR: Can't remove mapped device"       exit 1     fi   fi }  check_fs(){   blkid /dev/mapper/stegano_$name >/dev/null 2>&1   if [ $? -ne 0 ] ; then     return   fi   e2fsck -n /dev/mapper/stegano_$name >/dev/null 2>&1   if [ $? -ne 0 ] ; then     return   fi   fs_ok="y"   return }  create_fs(){   if [ $fs_ok != "y" ] ; then     echo "Usable size is $usable_size Mb."     echo "No filesystem found, create new? (y/N)"     read a     if [ "$a" = "y" ] ; then       echo -n "Cleaning... "       dd if=/dev/urandom of=/dev/mapper/stegano_$name bs=512 count=$sectors status=none       mkfs.ext4 -F -q /dev/mapper/stegano_$name       echo "done"       if [ $? -eq 0 ] ; then         fs_ok="y"       fi     fi   fi }    map_file(){    key=""   enter_pass    offset=0   nsym=4   while [ $offset -lt 20000000 ] ; do     sub=$(echo -n $tmp | head -c $nsym)     offset=$((0x$sub))     nsym=$(($nsym + 1))   done   while [ $offset -gt 60000000 ] ; do     offset=$(($offset / 2))   done    tailer=0   nsym=4   while [ $tailer -lt 20000000 ] ; do     sub=$(echo -n $tmp | tail -c $nsym)     tailer=$((0x$sub))     nsym=$(($nsym + 1))   done   while [ $tailer -gt 60000000 ] ; do     tailer=$(($tailer / 2))   done    filesize=$(stat --format="%s" "$file")    usable_size=$(( ($filesize - $offset - $tailer) / 1024 / 1024 ))   if [ $usable_size -lt 10 ] ; then     echo "Usable size too small! Select other file"     exit 1   fi    sectors=$(( ($filesize - $offset - $tailer) / 512 ))   loop=$(losetup -f --show --offset $offset --size $(($sectors * 512)) "$file")    if [ "x$loop" != "x" ] ; then     name=$(basename $loop)     sectors=$(cat /sys/class/block/$name/size)      if [ $sectors -gt 0 ] ; then       echo "0 $sectors crypt $cipher $key 0 $loop 0" \         | dmsetup create stegano_$name       if [ -b "/dev/mapper/stegano_$name" ] ; then          fs_ok="n"         check_fs         create_fs          if [ $fs_ok = "y" ] ; then           dir_ok="n"           check_dir            if [ "$dir_ok" = "y" ] ; then             mount_ok="n"             mount_dir             if [ "$mount_ok" = "y" ] ; then               echo "Success: mounted at $dir"               exit 0             fi           fi            remove_map           losetup -d $loop           exit 0          else           unmap_file         fi       else         echo "ERROR: Something wrong"         exit 1       fi     fi   fi }  unmap_file(){   name=$(basename $loop)    fs=$(mount | grep "/dev/mapper/stegano_$name" | awk '{print $3}')   if [ "x$fs" != "x" ] ; then     umount $fs     if [ $? -ne 0 ] ; then       echo "Still mounted as $fs"       exit 1     fi   fi    remove_map   losetup -d $loop   echo "Unmount device"   exit 0 } #################################  file_ok="n" check_file  if [ $file_ok = "y" ] ; then    is_mapped="n"   check_map    if [ "$is_mapped" = "n" ] ; then     map_file   else     unmap_file   fi  fi 

При вводе другого пароля скрытый диск будет создан заново, с затиранием данных.

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

ЗЫ: закинул на Гитхаб: https://github.com/JBFW/stegodisk


ссылка на оригинал статьи https://habr.com/ru/articles/896236/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *