1. Как это работает
Для начала необходимо освоить несколько полезных команд
Форматирование тома с опцией шифрования
# mkfs.ext4 -O encrypt /dev/xxx
Включение опции шифрования на существующий том
# tune2fs -O encrypt /dev/xxx
Создание ключа шифрования
# mount /dev/xxx /mnt/xxx
$ e4crypt add_key
Enter passphrase (echo disabled):
Added key with descriptor [8e679e4449bb9235]
При создании ключа том с поддержкой шифрования должен быть примонтирован, иначе e4crypt выдаст ошибку “No salt values available”. Если примонтировано несколько томов с опцией encrypt, то будут созданы ключи для каждого. Утилита e4crypt входит в состав e2fsprogs.
Ключи добавляются в Linux Kernel Keyring [1].
Чтение списка ключей
$ keyctl show
Session Keyring
771961813 --alswrv 1000 65534 keyring: _uid_ses.1000
771026675 --alswrv 1000 65534 \_ keyring: _uid.1000
803843970 --alsw-v 1000 1000 \_ logon: ext4:8e679e4449bb9235
Ключи, используемые для шифрования, имеют тип “logon”. Содержимое (payload) ключей такого типа недоступно из пространства пользователя — keyctl команды read, pipe, print вернут ошибку. В данном примере у ключа префикс “ext4”, но может быть и “fscrypt”. Если keyctl отсутствует в системе, то необходимо установить пакет keyutils.
Создание зашифрованной директории
$ mkdir /mnt/xxx/encrypted_folder
$ e4crypt set_policy 8e679e4449bb9235 /mnt/xxx/encrypted_folder/
Key with descriptor [8e679e4449bb9235] applied to /mnt/xxx/encrypted_folder/.
Здесь в команду set_policy передается дескриптор созданного ключа без указания префикса (ext4) и типа (logon). Одним и тем же ключом можно зашифровать несколько директорий. Для шифрования разных директорий можно использовать разные ключи. Чтобы узнать, каким ключом зашифрована директория, необходимо выполнить команду:
$ e4crypt get_policy /mnt/xxx/encrypted_folder/
/mnt/xxx/encrypted_folder/: 8e679e4449bb9235
Установить другую политику безопасности на зашифрованную директорию не получится:
$ e4crypt add_key
Enter passphrase (echo disabled):
Added key with descriptor [9dafe822ae6e7994]
$ e4crypt set_policy 9dafe822ae6e7994 /mnt/xxx/encrypted_folder/
Error [Invalid argument] setting policy.
The key descriptor [9dafe822ae6e7994] may not match the existing encryption context for directory [/mnt/xxx/encrypted_folder/].
Зато такую директорию можно беспрепятственно удалить:
$ rm -rf /mnt/xxx/encrypted_folder/
$ ll /mnt/xxx
total 24
drwxr-xr-x 3 user user 4096 Apr 21 15:14 ./
drwxr-xr-x 4 root root 4096 Mar 29 15:30 ../
drwx------ 2 root root 16384 Apr 17 12:41 lost+found/
$
Шифрование файла
$ echo "My secret file content" > /mnt/xxx/encrypted_folder/my_secrets.txt
$ cat /mnt/xxx/encrypted_folder/my_secrets.txt
My secret file content
$ ll /mnt/xxx/encrypted_folder/
total 12
drwxr-xr-x 2 user user 4096 Apr 20 14:25 ./
drwxr-xr-x 5 user user 4096 Apr 20 14:15 ../
-rw-r--r-- 1 user user 23 Apr 20 14:26 my_secrets.txt
Имена файлов в директории и содержимое файла будут доступны, пока в хранилище ключей существует ключ, которым была зашифрована директория. После аннулирования ключа доступ к директории будет сильно ограничен:
$ keyctl revoke 803843970
$ keyctl show
Session Keyring
771961813 --alswrv 1000 65534 keyring: _uid_ses.1000
771026675 --alswrv 1000 65534 \_ keyring: _uid.1000
803843970: key inaccessible (Key has been revoked)
Ключ аннулирован, читаем содержимое директории:
$ ll /mnt/xxx/encrypted_folder/
total 12
drwxr-xr-x 2 user user 4096 Apr 20 14:25 ./
drwxr-xr-x 5 user user 4096 Apr 20 14:15 ../
-rw-r--r-- 1 user user 23 Apr 20 14:26 BhqTNRNHDBwpa9S1qCaXwC
Имя файла уже абырвалг. Но всё-таки попробуем прочитать файл:
$ cat /mnt/xxx/encrypted_folder/BhqTNRNHDBwpa9S1qCaXwC
cat: /mnt/xxx/encrypted_folder/BhqTNRNHDBwpa9S1qCaXwC: Required key not available
NOTE: в Ubuntu 17.04 (kernel 4.10.0-19) директория остается доступной после удаления ключа до перемонтирования.
$ keyctl show
Session Keyring
771961813 --alswrv 1000 65534 keyring: _uid_ses.1000
771026675 --alswrv 1000 65534 \_ keyring: _uid.1000
$ e4crypt get_policy /mnt/xxx/encrypted_folder/
/mnt/xxx/encrypted_folder/: 8e679e4449bb9235
Директория зашифрована ключом с дескриптором “8e679e4449bb9235”. Ключ отсутствует в хранилище. Несмотря на это, директория и содержимое файла в свободном доступе.
$ ll /mnt/xxx/encrypted_folder/
total 12
drwxr-xr-x 2 user user 4096 Apr 20 14:25 ./
drwxr-xr-x 5 user user 4096 Apr 20 14:15 ../
-rw-r--r-- 1 user user 23 Apr 20 14:26 my_secrets.txt
$ cat /mnt/xxx/encrypted_folder/my_secrets.txt
My secret file content
Перемонтирование:
# umount /dev/xxx
# mount /dev/xxx /mnt/xxx
$ ll /mnt/xxx/encrypted_folder/
total 12
drwxr-xr-x 2 user user 4096 Apr 20 14:25 ./
drwxr-xr-x 5 user user 4096 Apr 20 14:15 ../
-rw-r--r-- 1 user user 23 Apr 20 14:26 BhqTNRNHDBwpa9S1qCaXwC
2. Изменения в файловой системе
В Суперблоке: набор опций s_feature_incompat на томе с поддержкой шифрования содержит флаг EXT4_FEATURE_INCOMPAT_ENCRYPT,
s_encrypt_algos[4] — хранит алгоритмы шифрования; на данный момент это:
s_encrypt_algos[0] = EXT4_ENCRYPTION_MODE_AES_256_XTS;
s_encrypt_algos[1] = EXT4_ENCRYPTION_MODE_AES_256_CTS;
s_encrypt_pw_salt — также задается при форматировании.
В айноде: i_flags содержит флаг EXT4_ENCRYPT_FL и именно по нему можно определить, что объект зашифрован.
Структура зашифрованной директории
Чтобы прочитать содержимое директории, нужно по ее айноду определить ее местоположение на диске.
1. Определение номера айнода:
$ stat /mnt/xxx/encrypted_folder/
File: /mnt/xxx/encrypted_folder/
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 811h/2065d Inode: 14 Links: 2
2. Поиск айнода в таблице айнодов.
Айнод 14 принадлежит 0-й группе, поэтому необходимо прочитать таблицу дескрипторов 0-й группы и найти в ней номер блока таблицы айнодов. Таблица дескрипторов 0-й группы находится в кластере, следующим за суперблоком:
# dd if=/dev/xxx of=gdt bs=4096 count=1 skip=1
Рис. 1. Таблица дескрипторов 0-й группы
Вначале пропускаем номера кластеров битмапа блоков и битмапа айнодов, номер кластера начала таблицы айнодов читаем по смещению 8 байт от начала таблицы — 0x00000424 (1060) в BigEndian формате. Айнод директории = 14, при размере айнода в 256 байт в таблице он будет находиться по смещению 0x0D00 от ее начала. Таким образом, достаточно прочитать только 1-й кластер таблицы айнодов:
# dd if=/dev/xxx of=itable bs=4096 count=1 skip=1060
Рис. 2. Айнод зашифрованной директории.
В айноде определяем начало поля i_block[]. Т.к. это ext4, то в первых 2 байтах i_block находится заголовок дерева экстентов — 0xF30A. Далее можно увидеть номер блока, в котором хранится зашифрованная директория — 0x00000402 (1026). (На рисунке выделено не всё поле i_block, а только информативные 24 байта — остальные 36 байт заполнены нулями.)
3. Чтение блока директории:
# dd if=/dev/xxx of=dirdata bs=4096 count=1 skip=1026
Рис. 3. Дамп зашифрованной директории.
Подробнее: первые две entry (выделены красным) — это записи “.” и “..”, соответственно, текущая и родительская директории. У текущей директории айнод 0x0000000E, длина записи 0x000C байт, количество символов в имени файла — 01 и тип entry 02 — это директория. Далее следует имя директории, выровненное по 4-байтовой границе — 2E000000 (2E соответствует символу ‘.’ — точка).
Следующая, родительская директория, имеет айнод 0x00000002 (корневая директория), аналогичная длина записи 0x000C, в имени 02 символа, тип также 02, после чего идет имя директории — 2E2E0000 (две точки).
Наконец, последняя entry в данной директории имеет айнод 0x0000000F, размер записи 0x0FDC, количество символов в имени 0x10, тип 01 — это и есть зашифрованный файл. Как видно его имя не соответствует созданному my_secrets.txt. К тому же, в исходном имени файла всего 14 символов, а не 16 как здесь.
NOTE: особенно внимательные читатели с калькулятором могли заметить, что т.к. зашифрованный файл является последней entry в директории, то его размер записи должен ссылаться на границу блока. Однако, 0x1000 — 0xC — 0xC = 0xFE8, а не 0xFDC. Это связано с тем, что том создавался с опцией “metadata_csum”, которая задается по умолчанию, начиная с Ubuntu 16.10. При включении этой опции в конце каждого блока директории создается 12-байтовая структура, содержащая контрольную сумму этого блока.
4. Чтение зашифрованного файла.
Из дампа директории определяем, что файл имеет айнод 15 (0xF). Ищем его в таблице айнодов и аналогично определяем его положение на диске:
Рис. 4. Айнод зашифрованного файла.
Читаем содержимое кластера 0x0000AA00 (43520)
# dd if=/dev/xxx of=filedata bs=4096 count=1 skip=43520
Рис. 5. Содержимое зашифрованного файла
И это совсем не соответствует записанной в файл информации. Настоящий размер файла можно прочитать в поле i_size айнода (отмечен синим прямоугольником на рис. 4): 0x00000017 — именно столько было записано командой echo “My secret file content” + символ перевода строки 0x0A.
3. Расшифровка
Расшифровка имени файла
Согласно EXT4 Encryption Design Document [2] расшифровка имен файлов выполняется в два этапа:
1. DerivedKey = AES-128-ECB(data=MasterKey, key=DirNonce);
2. EncFileName = AES-256-CBC-CTS(data=DecFileName, key=DerivedKey);
Т.е. на первом этапе надо получить ключ для расшифровки. Для этого используются данные Мастер-ключа, созданного при добавлении ключа в keyring, которые шифруются по AES-ECB 128-битным ключом DirNonce. На втором этапе используется фиксированный вектор инициализации (IV), заполненный нулями. Для AES-ECB вектор инициализации не нужен.
Что такое DirNonce? В айноде зашифрованной директории есть extended attribute.
Рис. 6. Айнод зашифрованной директории и его extended attribute
При размере айнода в 256 байт в структуре остается около сотни неиспользуемых байт (0x100 — EXT2_GOOD_OLD_INODE_SIZE — i_extra_size), в которых можно хранить информацию (красная область на рис. 6). Как видно по заголовку 0xEA020000 в первых четырех байтах этой области, здесь хранится extended attribute с индексом 09, данные которого смещены на 0x40 байт от заголовка и имеют размер 0x1C. Область данных поделена на 3 зоны: в первой (01 01 04 00) записаны алгоритмы, по которым был зашифрован айнод. Во второй — хранится 8 байт (8E 67 9E 44 49 BB 92 35), повторяющие дескриптор ключа. В третьей — содержится 16-байтовый одноразовый код (нонс [3]), используемый при шифровании Мастер-ключа.
Таким образом, для расшифровки имени файла, необходимо:
1) прочитать значение безымянного extended attribute директории с индексом 9 — получаем нонс директории;
2) по алгоритму AES-ECB зашифровать данные Мастер-ключа, используя в качестве ключа 128 бит нонса директории;
3) по алгоритму AES-CBC-CTS расшифровать имя файла, используя в качестве ключа первые 256 бит (половину) ключа, полученного на предыдущем этапе.
Расшифровка содержимого файла
Выполняется аналогично процедуре расшифровки имени файла, за исключением того, что в качестве нонса используется значение extended attribute, полученное из айнода файла. И вместо CBC содержимое дешифруется по алгоритму AES-XTS с полным 64-байтовым ключом. В качестве IV используется Logical Block Offset относительно начала файла
Рис. 7. Айнод зашифрованного файла и его extended attribute.
Сравнивая значение extended attribute зашифрованного файла и директории, можно заметить, что их нонсы различаются, в то время как алгоритмы шифрования и дескрипторы ключей совпадают (желтая и синяя зоны на рисунках).
Содержимое файлов шифруется постранично, поэтому для расшифровки контента обязательно использовать целый кластер файла (4K), а не размер, указанный в поле i_size айнода.
4. Реализация
Реализация дешифратора выполнена на основе Linux Kernel Crypto API [4]. В цепочке используется два вида шифраторов в зависимости от того, что прописано в /proc/crypto для алгоритмов ebc(aes), cts(cbc(aes)), xts(aes). Рассматриваем ядро 4.10.0-19: шифр ebc реализуется через blkcipher, cts(cbc) и xts — через skcipher:
name: ecb(aes)
driver: ecb(aes-aesni)
module: kernel
priority: 300
internal: no
type: blkcipher
blocksize: 16
min keysize: 16
max keysize: 32
ivsize: 0
geniv: default
name: cts(cbc(aes))
driver: cts(cbc-aes-aesni)
module: kernel
priority: 400
internal: no
type: skcipher
async: yes
blocksize: 16
min keysize: 16
max keysize: 32
ivsize: 16
chunksize: 16
name: xts(aes)
driver: xts-aes-aesni
module: aesni_intel
priority: 401
internal: no
type: skcipher
async: yes
blocksize: 16
min keysize: 32
max keysize: 64
ivsize: 16
chunksize: 16
typedef enum { ENCRYPT, DECRYPT } cipher_mode;
static int do_blkcrypt(const u8* cipher, const u8* key, u32 key_len,
void* iv, void* dst, void* src, size_t src_len, cipher_mode mode)
{
int res;
struct crypto_blkcipher* blk;
struct blkcipher_desc desc;
struct scatterlist sg_src, sg_dst;
blk = crypto_alloc_blkcipher(cipher, 0, 0);
if (IS_ERR(blk))
{
printk(KERN_WARNING "Failed to initialize blkcipher mode %s\n", cipher);
return PTR_ERR(blk);
}
res = crypto_blkcipher_setkey(blk, key, key_len);
if (res)
{
printk(KERN_WARNING "Failed to set key. len=%#x\n", key_len);
crypto_free_blkcipher(blk);
return res;
}
crypto_blkcipher_set_iv(blk, iv, 16);
sg_init_one(&sg_src, src, src_len);
sg_init_one(&sg_dst, dst, src_len);
desc.tfm = blk;
desc.flags = 0;
if (mode == ENCRYPT)
res = crypto_blkcipher_encrypt(&desc, &sg_dst, &sg_src, src_len);
else
res = crypto_blkcipher_decrypt(&desc, &sg_dst, &sg_src, src_len);
crypto_free_blkcipher(blk);
return res;
}
struct tcrypt_result {
struct completion completion;
int err;
};
static void crypt_complete_cb(struct crypto_async_request* req, int error)
{
struct tcrypt_result* res = req->data;
if (error == -EINPROGRESS)
return;
res->err = error;
complete(&res->completion);
}
static int do_skcrypt(const u8* cipher, const u8* key, u32 key_len,
void* iv, void* dst, void* src, size_t src_len, cipher_mode mode)
{
struct scatterlist src_sg, dst_sg;
struct crypto_skcipher* tfm;
struct skcipher_request* req = 0;
struct tcrypt_result crypt_res;
int res = -EFAULT;
tfm = crypto_alloc_skcipher(cipher, 0, 0);
if (IS_ERR(tfm))
{
printk(KERN_WARNING "Failed to initialize skcipher mode %s\n", cipher);
res = PTR_ERR(tfm);
tfm = NULL;
goto out;
}
req = skcipher_request_alloc(tfm, GFP_NOFS);
if (!req)
{
printk(KERN_WARNING "Couldn't allocate skcipher handle\n");
res = -ENOMEM;
goto out;
}
skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP,
crypt_complete_cb, &crypt_res);
if (crypto_skcipher_setkey(tfm, key, key_len))
{
printk(KERN_WARNING "Failed to set key\n");
res = -EINVAL;
goto out;
}
sg_init_one(&src_sg, src, src_len);
sg_init_one(&dst_sg, dst, src_len);
skcipher_request_set_crypt(req, &src_sg, &dst_sg, src_len, iv);
init_completion(&crypt_res.completion);
if (mode == ENCRYPT)
res = crypto_skcipher_encrypt(req);
else
res = crypto_skcipher_decrypt(req);
switch (res)
{
case 0: break;
case -EINPROGRESS:
case -EBUSY:
wait_for_completion(&crypt_res.completion);
if (!res && !crypt_res.err)
{
reinit_completion(&crypt_res.completion);
break;
}
default:
printk("Skcipher %scrypt returned with err = %d, result %#x\n",
mode == ENCRYPT ? "en" : "de", res, crypt_res.err);
break;
}
out:
if (tfm)
crypto_free_skcipher(tfm);
if (req)
skcipher_request_free(req);
return res;
}
#define MASTER_KEY_SIZE 64
static int GetMasterKey(const u8* descriptor, u8* raw)
{
struct key* keyring_key = NULL;
const struct user_key_payload* ukp;
struct fscrypt_key* master_key;
keyring_key = request_key(&key_type_logon, descriptor, NULL);
if (IS_ERR(keyring_key))
return -EINVAL;
if (keyring_key->type != &key_type_logon)
{
printk_once(KERN_WARNING "%s: key type must be 'logon'\n", __func__);
return -EINVAL;
}
down_read(&keyring_key->sem);
ukp = user_key_payload(keyring_key);
master_key = (struct fscrypt_key*)ukp->data;
up_read(&keyring_key->sem);
if (master_key->size != MASTER_KEY_SIZE)
{
printk(KERN_WARNING "Wrong Master key size %#x\n", master_key->size);
return -EINVAL;
}
memcpy(raw, master_key->raw, master_key->size);
return 0;
}
NOTE: В версиях ядра младше 4.4 отсутствует функция user_key_payload. Данные ключа можно прочитать непосредственно из struct key* keyring_key.
Расшифровка имени файла
int err;
u8 iv[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
u8 nonce_dir[16] = { ... };
u8 master_key[64], derived_key[64];
u8 dec_file_name[] = { ... };
u8 enc_file_name[sizeof(dec_file_name)];
err = do_blkcrypt("ecb(aes)", nonce_dir, 16, iv, derived_key, master_key,
MASTER_KEY_SIZE, ENCRYPT);
if (err)
return err;
err = do_skcrypt("cts(cbc(aes))", derived_key, MASTER_KEY_SIZE / 2, iv,
dec_file_name, enc_file_name, sizeof(dec_file_name), DECRYPT);
return err;
Расшифровка контента
Для упрощения опущена работа с памятью. Предположим, 2 x PAGE_SIZE нам дали на стеке.
u8 nonce_file[16] = { ... };
u8 enc_file_data[PAGE_SIZE] = { ... };
u8 dec_file_data[PAGE_SIZE];
err = do_blkcrypt("ecb(aes)", nonce_file, 16, iv, derived_key, master_key,
MASTER_KEY_SIZE, ENCRYPT);
if (err)
return err;
err = do_skcrypt("xts(aes)", derived_key, MASTER_KEY_SIZE, iv,
dec_file_data, enc_file_data, PAGE_SIZE, DECRYPT);
return err;
Используемые заголовочные файлы (актуально для 4.10.0-19)
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/fscrypto.h>
Makefile
obj-m += ciphertest.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
5. Результаты
Исходные данные:
u8 master_key[MASTER_KEY_SIZE] = {
0xa5, 0xb5, 0xc9, 0x23, 0x02, 0x14, 0xfc, 0xf7,
0x28, 0xdc, 0x90, 0x25, 0x24, 0x9e, 0xe6, 0xbc,
0x7c, 0xa8, 0xf8, 0xe1, 0x94, 0xf6, 0x67, 0x32,
0x33, 0xc4, 0xc1, 0xe8, 0x78, 0x59, 0xab, 0xfb,
0xae, 0xb0, 0xbf, 0x5d, 0x2c, 0x69, 0xc3, 0x8f,
0x51, 0x37, 0x26, 0x3f, 0xd1, 0xce, 0x37, 0xef,
0x3f, 0x80, 0xe3, 0x2d, 0xd5, 0xfd, 0x78, 0x45,
0x62, 0xf3, 0xa5, 0x24, 0x6b, 0xcf, 0x4a, 0x88
};
u8 enc_file_name[] = {
0x41, 0xa8, 0x4e, 0x4d, 0xd4, 0x1c, 0x43, 0x00,
0xa7, 0x5a, 0x2f, 0xd5, 0xaa, 0xa0, 0x5d, 0xb0
};
u8 nonce_dir[] = {
0x37, 0xba, 0x14, 0x16, 0x3e, 0xa8, 0xd5, 0x48,
0xd1, 0x3c, 0xb5, 0x6a, 0x01, 0xb7, 0x7c, 0x41
};
u8 nonce_file[] = {
0x61, 0x63, 0xb8, 0x31, 0xf4, 0xf5, 0xfc, 0x99,
0x1e, 0x3c, 0xf1, 0x8a, 0x23, 0xaf, 0x1e, 0xa8
};
Закодированное имя файла enc_file_name получено из дампа директории (рис. 3).
Нонс директории nonce_dir получен из дампа айнода директории (рис. 6)
Нонс файла nonce_file получен из дампа айнода файла (рис. 7)
Мастер-ключ показан здесь полностью для наглядности. Его можно получить при отладке e4crypt:
Результат работы созданного драйвера
[2] EXT4 Encryption Design Document, docs.google.com/document/d/1ft26lUQyuSpiu6VleP70_npaWdRfXFoNnB8JYnykNTg/edit
[3] Wikipedia — Nonce, ru.wikipedia.org/wiki/Nonce
[4] Linux Kernel Crypto API, www.kernel.org/doc/html/latest/crypto/index.html
Комментарии (23)
Barafu
01.05.2017 23:54+3Зря не озвучили, зачем оно вообще всё надо. Грузиться с него нельзя, отдельные папки шифровать и без него способов много.
saipr
02.05.2017 12:49А может целесооборазнее использовать это
CryptoAPI ядра Linux: разработка и применение российской криптографии?
shs
03.05.2017 00:471. Зачем нужно шифрование на уровне файловой системы? Ну, как минимум, для улучшения производительности без использования сторонних продуктов. Это чисто мое мнение, а лучше спросить у Гугла, как у заказчика.
2. Зачем с него грузиться, я, честно, вообще не задумывался. Подозреваю, что моя паранойя еще не прогрессирует
3. Шифровать отдельные папки способы есть, несомненно. Но, может, пришло уже время выкинуть этот бубен, когда есть способ сделать это из коробки.Barafu
03.05.2017 13:47Не-не-не. Шифрование на уровне около файловой системы в Линуксе было испокон веков, от юзерспейсной ecryptfs до монументального LUKS. И да, с последнего можно грузиться. На ноуте можно оставить незащищённым только GRUB, который, однако, защищён цифровой подписью secureboot. В результате, если злоумышленник незаметно получит физический доступ к машине, он не сможет не только ничего открыть, но и оставить программную закладку тоже. А физическую закладку, имхо, труднее сделать и легче найти.
Из коробки — тоже сильно сказано. Нужна файловая система, которой уже может и не быть, и к ней набор утилит, которых ещё может не быть. К концу 2018, когда эти улиты осядут в медленных дистрибутивах, уже, наверное, и сервера будут делать на Btrfs.
Так что речь идёт о довольно-таки специфическом решении, и вопрос "А зачем оно надо, когда есть ecryptfs и LUKS?" стоит по-прежнему. Вкупе с описанными ниже сложностями с бекапом всё равно для серьёзного дела будут создавать отдельный раздел для зашифрованного. Чтобы бекапить без проблем.
К тому же мне очень сильно не нравится решение "без ключа — видны папки с кракозябрами". Зачем они нужны? Чтобы find в них застревал? Чтобы объём зашифрованного добра утёк? Не знаю.shs
04.05.2017 00:221. Для бекапа проблем нет. Могу долго и нудно про это рассказывать (вкратце уже изложил ниже), но это совершенно другая тема.
2. ecryptfs — насколько я понял, шифрование в ext4 как раз реализовано на ее основе.
3. LUKS, насколько помню, шифрует сразу всё и сразу, т.е. это не совсем то.
4. Если злоумышленник вроде меня снимет dd со всего раздела, то я навскидку не могу придумать, как расшифровать содержимое директории, владея всеми этими заумными аббревиатурами. Ключи всё-таки ого-го.
5. Видны папки с кракозябрами? Это еще пол-дела. Эти кракозябры совершенно не соответствуют тому, что непосредственно прописано в direntry, т.е. для вывода пользователю оно еще раз шифруется по типу base64, дабы исключить невалидные символы в именах. А для find вообще не должно быть вопросов: ну получит он restrict, ему же лучше
konchok
02.05.2017 14:57Из статьи не понял как получить содержимое файлов в зашифрованном виде?
Это совершенно не подходит для резервного копирования.
Имя файла уже абырвалг. Но всё-таки попробуем прочитать файл:
$ cat /mnt/xxx/encrypted_folder/BhqTNRNHDBwpa9S1qCaXwC
cat: /mnt/xxx/encrypted_folder/BhqTNRNHDBwpa9S1qCaXwC: Required key not available
shs
02.05.2017 15:46Хороший вопрос. Резервное копирование — это вообще отдельная тема.
В данном примере содержимое зашифрованного файла получается при непосредственном чтении кластеров, которые принадлежат этому айноду — сначала необходимо найти айнод в таблице и затем пройти по его дереву экстентов, читая занятые кластера. Обратите внимание на рис. 4, где показан айнод зашированного файла и выделен его один единственный кластер. Здесь рассмотрен очень простой случай. Но в целом — задача, мягко говоря, не самая тривиальная.
Что же касается резервного копирования, то выполнение этой операции через readdir() с последующим read/write здесь не годится, если я правильно понял вопрос. Придется либо подружиться с деревом экстентов, либо вычитывать битмап блоков для каждой группы дескрипторов и копировать занятые кластера.
Erelecano
Необходимо отметить, что для всего этого требуется e2fsprogs версии >=1.43, а в текущем LTS Ubuntu(16.04) мы имеем 1.42.13 и при попытке включить криптацию получим
Так что версия ядра нам никак не поможет, если мы не станем разводить у себя помойку и тащить столь важный пакет не из родных репозиториев.
Таким образом в серьезных серверных дистрибутивах, а не в тестовых версиях(каковыми являются у Ubuntu non-LTS), мы получим эту возможность только с выходом Debian 9(где e2fsprogs 1.43.4), а для Ubuntu только в 18.04 LTS.
Haarolean
Почему обязательно разводить помойку? Можно найти репозиторий чтоб не тянуть кучу ненужных зависимостей или поставить вовсе не из репозитория.
Erelecano
> поставить вовсе не из репозитория.
Вот это и называется помойка.
Haarolean
Почему же? У вас весь софт из репозиториев? Становится ли моя система помойкой если я поставлю хотя бы одну программу не из репозитория, потому что разработчик не озадачился этим вопросом?
alexkunin
А потом при апдейте/апгрейде системы вы должны кроме команд, присущих вашему дистрибутиву, вручную обновлять весь такой «отдельно поставленный» софт, с ручным разрешением всех возможных конфликтов и т.д. А если передадите систему другому админу, нужно будет ему отдельно дать список таких вот «закладок», их источников и т.д.
Центральный репозиторий на то и существует, чтобы иметь набор гарантированно совместимых пакетов с единообразной системой инсталляции и деинсталляции.
Haarolean
Я прекрасно осведомлен и понимаю. Но что же делать — отказываться от огромной доли софта, потому что его придется обновлять вручную? Или обрекать свою систему «помойкой», как выразился Erelecano?
В случае с одной библиотекой тоже не вижу проблем, в 18.04 можно будет от этой «закладки» отказаться, если шифрование уже сейчас так необходимо.
alexkunin
Так вы только с термином не согласны? Вопрос исчерпан, стало быть. Назовите «ручником», «зоопарком», «смешанной инсталляцией» — смысл не изменится, перфекционизм поломан, а заодно и целостность системы.
Haarolean
Нет, не только. Это сферический линукс в вакууме — иметь весь софт из репозиториев, если список не ограничивается парой позицией. Даже если учитывать не только десктоп.
Erelecano
Это нормальный сервер и десктоп имеют софт только из репозиториев. Даже если этот репозиторий ваш собственный. За установку чего-то из исходников прямо на сервере я лично увольнял сотрудников, как проф.непригодных.
Нужно понимать, что у вас нет опыта работы с серверами, а у меня опыт работы с GNU/Linux 17 лет, так что мое мнение и мой подход весомей, чем ваше вредительство.
Haarolean
Не вижу смысла на десктопе делать собственный репозиторий из десятков программ, авторы которых не озаботились поставкой своего софта в репозитории. От этого ничего не изменится. А телеграм давно в репозиториях поставляется? Упс. Судя по вашей карме и комментариям, вредитель здесь явно не я :) /thread
Erelecano
А телеграм не нужен установленный, для отправки сообщений от бота, вот ведь неожиданность!
То что вы не видите смысла в том, что обязан делать любой админ я уже понял, вы — админ локалхоста и мамкин какир, когда вас возьмут хотя бы помощником попингуя в контору «Рога и копыта», тогда вам объяснят, возможно при помощи ног, а возможно при помощи увольнений, что весь софт должен ставиться и обновляться штатными средствами.
А на карму можете дальше дрочить, вот только мои статьи люди читают, а у вас чистый акк и тупые комментарии выдающие глуповатого ребенка.
vvzvlad
Вам стоит добавлять "для критичного сервера на продакшене" для каждого вашего комментария. Подход правильный, но на куче платформ излишне строгий.
Erelecano
Ровно такой же подход должен быть и на десктопе. А помойку разводить можно в lxc-тазах, если хочется помойки. А десктоп должен работать, тут вам не виндовс.
h31
Никто не мешает поставить tune2fs и другие утилиты в отдельную директорию. Тогда система продолжит использовать версию из репозитория, но при этом можно будет экспериментировать с последними фичами ФС.
По поводу помойки — да, в идеале все пакеты должны быть из репозитория, но жизнь диктует свои правила. Стандартный репозиторий хорош только для самых типовых задач, как только в требования попадает что-то хоть немного необычное — на сервере сразу появляется директория с самосбором. Те, кто поаккуратнее, собирают в пакеты, остальные просто делают набор директорий для каждой утилиты/библиотеки и кидают симлинки, если это нужно. Это то, что лично я видел в продакшене. Особенно это актуально для RHEL/SLES. Погуглите, убедитесь сами — большинство инструкций для этих дистрибутивов предлагают самому собирать нужные утилиты. К счастью, с появлением Docker стало немного попроще, но, сами понимаете, e2fsprogs в нем не запустишь.
Erelecano
> Никто не мешает поставить tune2fs и другие утилиты в отдельную директорию. Тогда система продолжит использовать версию из репозитория, но при этом можно будет экспериментировать с последними фичами ФС.
Ага, а потом штатный fsck из репозитория проверит вашу fs. И что накроется медным тазом, а что чугунной ванной в процессе науке неизвестно.
> на сервере сразу появляется директория с самосбором.
Как я уже писал выше я за такое людей просто увольнял, как несоответствующих занимаемой должности. Весь софт всегда должен ставиться и обновляться штатными методами. Если что-то критичное нужно версий отличных от того, что есть в репозиториях, то нужно поднимать свой и собирать. Если что-то отсутствует в репозиториях, то нужно собирать пакет и ставить его штатным образом.
А в случае с e2fsprogs беда в том, что пакет — критичный для системы и если его совать в свой репозиторий, то вам нужно будет автоматизировать его обновление, да еще самому следить за стабильность. Можно собирать какую-нибудь луашку с луаджитом в своей репе и обновлять когда есть критичные причины, можно nginx так или еще какой апач, но e2fsprogs слишком критичен, что бы тащить его из левых мест, собирать из исходников на месте или держать в своей репе. А потому данная фича сможет придти на мой ноутбук или сервера под моим контролем не раньше, чем она войдет в официальные репы.
shs
Не знаю, где находятся ваши родные репозитории, но для меня нет большой разницы между apt install и git clone https://github.com/tytso/e2fsprogs