image Паранойя не лечится! Но и не преследуется по закону. Поэтому в Linux Kernel 4.1 добавлена поддержка шифрования файловой системы ext4 на уровне отдельных файлов и директорий. Зашифровать можно только пустую директорию. Все файлы, которые будут созданы в такой директории, также будут зашифрованы. Шифруются только имена файлов и содержимое, метаданные не шифруются, inline data (когда данные файла, не превышающие по размеру 60 байт, хранятся в айноде) в файлах не поддерживается. Поскольку расшифровка содержимого файла выполняется непосредственно в памяти, шифрование доступно только в том случае, когда размер кластера совпадает с PAGE_SIZE, т.е. равен 4К.

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

image
Рис. 1. Таблица дескрипторов 0-й группы

Вначале пропускаем номера кластеров битмапа блоков и битмапа айнодов, номер кластера начала таблицы айнодов читаем по смещению 8 байт от начала таблицы — 0x00000424 (1060) в BigEndian формате. Айнод директории = 14, при размере айнода в 256 байт в таблице он будет находиться по смещению 0x0D00 от ее начала. Таким образом, достаточно прочитать только 1-й кластер таблицы айнодов:

# dd if=/dev/xxx of=itable bs=4096 count=1 skip=1060

image
Рис. 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

image
Рис. 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). Ищем его в таблице айнодов и аналогично определяем его положение на диске:

image
Рис. 4. Айнод зашифрованного файла.

Читаем содержимое кластера 0x0000AA00 (43520)

# dd if=/dev/xxx of=filedata bs=4096 count=1 skip=43520

image
Рис. 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.

image
Рис. 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 относительно начала файла

image
Рис. 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:

$ cat /proc/crypto
$ cat /proc/crypto
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

Реализация шифратора через blkcipher
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;
}


Реализация шифратора через skcipher
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;
}


Чтение данных (payload) Мастер-ключа
#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:

image

Результат работы созданного драйвера

image

Ссылки
Поделиться с друзьями
-->

Комментарии (23)


  1. Erelecano
    01.05.2017 16:30
    +4

    Необходимо отметить, что для всего этого требуется e2fsprogs версии >=1.43, а в текущем LTS Ubuntu(16.04) мы имеем 1.42.13 и при попытке включить криптацию получим

    tune2fs -O encrypt /dev/vda1
    tune2fs 1.42.13 (17-May-2015)
    Invalid filesystem option set: encrypt
    


    Так что версия ядра нам никак не поможет, если мы не станем разводить у себя помойку и тащить столь важный пакет не из родных репозиториев.

    Таким образом в серьезных серверных дистрибутивах, а не в тестовых версиях(каковыми являются у Ubuntu non-LTS), мы получим эту возможность только с выходом Debian 9(где e2fsprogs 1.43.4), а для Ubuntu только в 18.04 LTS.


    1. Haarolean
      01.05.2017 17:56
      -2

      Почему обязательно разводить помойку? Можно найти репозиторий чтоб не тянуть кучу ненужных зависимостей или поставить вовсе не из репозитория.


      1. Erelecano
        01.05.2017 17:59
        +12

        > поставить вовсе не из репозитория.

        Вот это и называется помойка.


        1. Haarolean
          01.05.2017 23:15
          -1

          Почему же? У вас весь софт из репозиториев? Становится ли моя система помойкой если я поставлю хотя бы одну программу не из репозитория, потому что разработчик не озадачился этим вопросом?


          1. alexkunin
            01.05.2017 23:23
            +4

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

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


            1. Haarolean
              01.05.2017 23:29

              Я прекрасно осведомлен и понимаю. Но что же делать — отказываться от огромной доли софта, потому что его придется обновлять вручную? Или обрекать свою систему «помойкой», как выразился Erelecano?

              В случае с одной библиотекой тоже не вижу проблем, в 18.04 можно будет от этой «закладки» отказаться, если шифрование уже сейчас так необходимо.


              1. alexkunin
                01.05.2017 23:48
                +1

                Так вы только с термином не согласны? Вопрос исчерпан, стало быть. Назовите «ручником», «зоопарком», «смешанной инсталляцией» — смысл не изменится, перфекционизм поломан, а заодно и целостность системы.


                1. Haarolean
                  02.05.2017 01:36

                  Нет, не только. Это сферический линукс в вакууме — иметь весь софт из репозиториев, если список не ограничивается парой позицией. Даже если учитывать не только десктоп.


                  1. Erelecano
                    02.05.2017 12:36

                    Это нормальный сервер и десктоп имеют софт только из репозиториев. Даже если этот репозиторий ваш собственный. За установку чего-то из исходников прямо на сервере я лично увольнял сотрудников, как проф.непригодных.
                    Нужно понимать, что у вас нет опыта работы с серверами, а у меня опыт работы с GNU/Linux 17 лет, так что мое мнение и мой подход весомей, чем ваше вредительство.


                    1. Haarolean
                      02.05.2017 13:41

                      Не вижу смысла на десктопе делать собственный репозиторий из десятков программ, авторы которых не озаботились поставкой своего софта в репозитории. От этого ничего не изменится. А телеграм давно в репозиториях поставляется? Упс. Судя по вашей карме и комментариям, вредитель здесь явно не я :) /thread


                      1. Erelecano
                        02.05.2017 13:44
                        -3

                        А телеграм не нужен установленный, для отправки сообщений от бота, вот ведь неожиданность!
                        То что вы не видите смысла в том, что обязан делать любой админ я уже понял, вы — админ локалхоста и мамкин какир, когда вас возьмут хотя бы помощником попингуя в контору «Рога и копыта», тогда вам объяснят, возможно при помощи ног, а возможно при помощи увольнений, что весь софт должен ставиться и обновляться штатными средствами.

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


                        1. vvzvlad
                          02.05.2017 18:19
                          +1

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


                          1. Erelecano
                            02.05.2017 18:30

                            Ровно такой же подход должен быть и на десктопе. А помойку разводить можно в lxc-тазах, если хочется помойки. А десктоп должен работать, тут вам не виндовс.


    1. h31
      02.05.2017 00:44
      +3

      Никто не мешает поставить tune2fs и другие утилиты в отдельную директорию. Тогда система продолжит использовать версию из репозитория, но при этом можно будет экспериментировать с последними фичами ФС.
      По поводу помойки — да, в идеале все пакеты должны быть из репозитория, но жизнь диктует свои правила. Стандартный репозиторий хорош только для самых типовых задач, как только в требования попадает что-то хоть немного необычное — на сервере сразу появляется директория с самосбором. Те, кто поаккуратнее, собирают в пакеты, остальные просто делают набор директорий для каждой утилиты/библиотеки и кидают симлинки, если это нужно. Это то, что лично я видел в продакшене. Особенно это актуально для RHEL/SLES. Погуглите, убедитесь сами — большинство инструкций для этих дистрибутивов предлагают самому собирать нужные утилиты. К счастью, с появлением Docker стало немного попроще, но, сами понимаете, e2fsprogs в нем не запустишь.


      1. Erelecano
        02.05.2017 15:54

        > Никто не мешает поставить tune2fs и другие утилиты в отдельную директорию. Тогда система продолжит использовать версию из репозитория, но при этом можно будет экспериментировать с последними фичами ФС.

        Ага, а потом штатный fsck из репозитория проверит вашу fs. И что накроется медным тазом, а что чугунной ванной в процессе науке неизвестно.

        > на сервере сразу появляется директория с самосбором.

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

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


    1. shs
      03.05.2017 00:30

      Так что версия ядра нам никак не поможет, если мы не станем разводить у себя помойку и тащить столь важный пакет не из родных репозиториев.

      Не знаю, где находятся ваши родные репозитории, но для меня нет большой разницы между apt install и git clone https://github.com/tytso/e2fsprogs


  1. Barafu
    01.05.2017 23:54
    +3

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


    1. saipr
      02.05.2017 12:49

      А может целесооборазнее использовать это
      CryptoAPI ядра Linux: разработка и применение российской криптографии?


    1. shs
      03.05.2017 00:47

      1. Зачем нужно шифрование на уровне файловой системы? Ну, как минимум, для улучшения производительности без использования сторонних продуктов. Это чисто мое мнение, а лучше спросить у Гугла, как у заказчика.
      2. Зачем с него грузиться, я, честно, вообще не задумывался. Подозреваю, что моя паранойя еще не прогрессирует
      3. Шифровать отдельные папки способы есть, несомненно. Но, может, пришло уже время выкинуть этот бубен, когда есть способ сделать это из коробки.


      1. Barafu
        03.05.2017 13:47

        Не-не-не. Шифрование на уровне около файловой системы в Линуксе было испокон веков, от юзерспейсной ecryptfs до монументального LUKS. И да, с последнего можно грузиться. На ноуте можно оставить незащищённым только GRUB, который, однако, защищён цифровой подписью secureboot. В результате, если злоумышленник незаметно получит физический доступ к машине, он не сможет не только ничего открыть, но и оставить программную закладку тоже. А физическую закладку, имхо, труднее сделать и легче найти.
        Из коробки — тоже сильно сказано. Нужна файловая система, которой уже может и не быть, и к ней набор утилит, которых ещё может не быть. К концу 2018, когда эти улиты осядут в медленных дистрибутивах, уже, наверное, и сервера будут делать на Btrfs.
        Так что речь идёт о довольно-таки специфическом решении, и вопрос "А зачем оно надо, когда есть ecryptfs и LUKS?" стоит по-прежнему. Вкупе с описанными ниже сложностями с бекапом всё равно для серьёзного дела будут создавать отдельный раздел для зашифрованного. Чтобы бекапить без проблем.
        К тому же мне очень сильно не нравится решение "без ключа — видны папки с кракозябрами". Зачем они нужны? Чтобы find в них застревал? Чтобы объём зашифрованного добра утёк? Не знаю.


        1. shs
          04.05.2017 00:22

          1. Для бекапа проблем нет. Могу долго и нудно про это рассказывать (вкратце уже изложил ниже), но это совершенно другая тема.
          2. ecryptfs — насколько я понял, шифрование в ext4 как раз реализовано на ее основе.
          3. LUKS, насколько помню, шифрует сразу всё и сразу, т.е. это не совсем то.
          4. Если злоумышленник вроде меня снимет dd со всего раздела, то я навскидку не могу придумать, как расшифровать содержимое директории, владея всеми этими заумными аббревиатурами. Ключи всё-таки ого-го.
          5. Видны папки с кракозябрами? Это еще пол-дела. Эти кракозябры совершенно не соответствуют тому, что непосредственно прописано в direntry, т.е. для вывода пользователю оно еще раз шифруется по типу base64, дабы исключить невалидные символы в именах. А для find вообще не должно быть вопросов: ну получит он restrict, ему же лучше


  1. konchok
    02.05.2017 14:57

    Из статьи не понял как получить содержимое файлов в зашифрованном виде?
    Это совершенно не подходит для резервного копирования.

    Имя файла уже абырвалг. Но всё-таки попробуем прочитать файл:
    $ cat /mnt/xxx/encrypted_folder/BhqTNRNHDBwpa9S1qCaXwC
    cat: /mnt/xxx/encrypted_folder/BhqTNRNHDBwpa9S1qCaXwC: Required key not available


  1. shs
    02.05.2017 15:46

    Хороший вопрос. Резервное копирование — это вообще отдельная тема.
    В данном примере содержимое зашифрованного файла получается при непосредственном чтении кластеров, которые принадлежат этому айноду — сначала необходимо найти айнод в таблице и затем пройти по его дереву экстентов, читая занятые кластера. Обратите внимание на рис. 4, где показан айнод зашированного файла и выделен его один единственный кластер. Здесь рассмотрен очень простой случай. Но в целом — задача, мягко говоря, не самая тривиальная.

    Что же касается резервного копирования, то выполнение этой операции через readdir() с последующим read/write здесь не годится, если я правильно понял вопрос. Придется либо подружиться с деревом экстентов, либо вычитывать битмап блоков для каждой группы дескрипторов и копировать занятые кластера.