Содержание

Шифрование файлов с помощью AES в OpenSSL

Рассмотрим как зашифровать и дешифровать текстовый файл алгоритмом с помощью OpenSSL и алгоритма AES-256-CBC.
Можно использовать два подхода: с явным ключом и IV или через пароль с PBKDF2, который автоматически генерирует ключ и вектор инициализации из пароля и случайной соли.

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

echo "Encrypt this message using OpenSSL now" > message.txt

Проверим содержимое файла:

❯ cat message.txt | xxd

00000000: 456e 6372 7970 7420 7468 6973 206d 6573  Encrypt this mes
00000010: 7361 6765 2075 7369 6e67 204f 7065 6e53  sage using OpenS
00000020: 534c 206e 6f77 0a                        SL now.

Сгенерируем ключ (KEY) и вектор инициализации (IV):

IV=$(openssl rand -hex 16)
KEY=$(openssl rand -hex 32)


echo $KEY $IV

9cfb54c0c2b5dd866ac0c0a7abd6b8c688bdca45c1f3aa132c008c71df4b24c6 30171b9a66eab28b098d4dd19e89ce85

IV (вектор инициализации) - 16 байт для AES-256-CBC.
Ключ - 32 байта для AES-256 (256 бит).

Зашифруем файл с помощью AES-256-CBC, используя заранее сгенерированные ключ и IV:

❯ openssl enc -aes-256-cbc -in message.txt -out message.bin -K $KEY -iv $IV

Посмотрим, что получилось:

❯ cat message.bin | xxd

00000000: e6bb 1d11 a342 c6cf 7060 ab3d bb32 f177  .....B..p`.=.2.w
00000010: ea02 9939 889c 0125 a13e 3f14 5575 55c3  ...9...%.>?.UuU.
00000020: 30f1 69ca 92d7 0204 f6b2 777a 7316 363f  0.i.......wzs.6?

Размер зашифрованного файла кратен 16 байтам (AES-блок).
Сообщение автоматически дополняется с помощью PKCS#7, чтобы последний блок был полным.

Используем те же ключ и IV, что были при шифровании, чтобы восстановить исходное сообщение:

❯ openssl enc -d -aes-256-cbc -in message.bin -out message.dec -K $KEY -iv $IV


❯ cat message.dec | xxd

00000000: 456e 6372 7970 7420 7468 6973 206d 6573  Encrypt this mes
00000010: 7361 6765 2075 7369 6e67 204f 7065 6e53  sage using OpenS
00000020: 534c 206e 6f77 0a                        SL now.

Файлы message.txt и message.dec идентичны. Значит все работает!

Теперь вместо явного указания KEY и IV мы будем использовать читаемый пароль.
OpenSSL с опцией -pbkdf2 сам преобразует пароль в ключ и IV через PBKDF2, используя случайную соль.

Шифруем файл, используя пароль MySecret123.

❯ openssl enc -aes-256-cbc -in message.txt -out message.bin -pass pass:MySecret123 -pbkdf2

Проверяем зашифрованный файл message.bin:

❯ cat message.bin | xxd

00000000: 5361 6c74 6564 5f5f e094 28d7 3836 c966  Salted__..(.86.f
00000010: b25e deb6 fb4b 1e16 e0ce 2b01 d9aa 68eb  .^...K....+...h.
00000020: 0e2d ca6f fe3f 47ad c135 379b 7be1 45f9  .-.o.?G..57.{.E.
00000030: 9d48 3557 4813 1a48 0030 991e 7eac dc7a  .H5WH..H.0..~..z

Структура файла:

  • Первые 8 байт: Salted__ - маркер, который означает, что файл зашифрован с солью.
  • Следующие 8 байт: случайную соль 0xe09428d73836c966, которая используется в PBKDF2 для генерации ключа и IV.
  • Остальное: зашифрованные данные.

Соль уникальна для каждого шифрования, поэтому даже при одинаковом пароле зашифрованный файл будет другим.

Расшифровываем файл:

❯ openssl enc -d -aes-256-cbc -in message.bin -out message.dec -pass pass:MySecret123 -pbkdf2

Проверяем результат:

❯ cat message.dec | xxd

00000000: 456e 6372 7970 7420 7468 6973 206d 6573  Encrypt this mes
00000010: 7361 6765 2075 7369 6e67 204f 7065 6e53  sage using OpenS
00000020: 534c 206e 6f77 0a                        SL now.

Иногда полезно знать точные значения ключа и IV, которые OpenSSL сгенерировал из пароля и соли с помощью PBKDF2.
Это позволяет расшифровывать данные без повторного использования пароля.

Получаем ключ и IV из пароля и конкретной соли:

❯ openssl enc -aes-256-cbc -pass pass:MySecret123 -pbkdf2 -P -S e09428d73836c966

salt=E09428D73836C966
key=F235FFB8CCB67EE4B7862BE9538229F4DF132335F26DE6EEC5602F94F4B8EC13
iv =E3C3C758EE36C702954E9196F24DB962

Сохраняем параметры в переменных окружения для удобства:

KEY=F235FFB8CCB67EE4B7862BE9538229F4DF132335F26DE6EEC5602F94F4B8EC13
IV=E3C3C758EE36C702954E9196F24DB962

Поскольку OpenSSL добавляет в файл первые 16 байт (Salted__ + соль), их нужно пропустить, чтобы расшифровать только зашифрованные данные:

❯ dd if=message.bin bs=1 skip=16 status=none | openssl enc -d -aes-256-cbc -K $KEY -iv $IV | xxd

00000000: 456e 6372 7970 7420 7468 6973 206d 6573  Encrypt this mes
00000010: 7361 6765 2075 7369 6e67 204f 7065 6e53  sage using OpenS
00000020: 534c 206e 6f77 0a                        SL now.

Похожее