Skip to main content

Функции шифрования

Данные функции реализуют шифрование и расшифровку данных с помощью AES (Advanced Encryption Standard) алгоритма.

Длина ключа зависит от режима шифрования. Он может быть длинной в 16, 24 и 32 байта для режимов шифрования -128-, -196- и -256- соответственно.

Длина инициализирующего вектора всегда 16 байт (лишние байты игнорируются).

Обратите внимание, что до версии ClickHouse 21.1 эти функции работали медленно.

encrypt

Функция поддерживает шифрование данных следующими режимами:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-ofb, aes-192-ofb, aes-256-ofb
  • aes-128-gcm, aes-192-gcm, aes-256-gcm
  • aes-128-ctr, aes-192-ctr, aes-256-ctr

Синтаксис

encrypt('mode', 'plaintext', 'key' [, iv, aad])

Аргументы

  • mode — режим шифрования. String.
  • plaintext — текст, который будет зашифрован. String.
  • key — ключ шифрования. String.
  • iv — инициализирующий вектор. Обязателен для -gcm режимов, для остальных режимов необязателен. String.
  • aad — дополнительные аутентифицированные данные. Не шифруются, но влияют на расшифровку. Параметр работает только с -gcm режимами. Для остальных вызовет исключение. String.

Возвращаемое значение

  • Бинарная зашифрованная строка. String.

Примеры

Создадим такую таблицу:

Запрос:

CREATE TABLE encryption_test
(
`comment` String,
`secret` String
)
ENGINE = Memory;

Вставим некоторые данные (замечание: не храните ключи или инициализирующие векторы в базе данных, так как это компрометирует всю концепцию шифрования), также хранение "подсказок" небезопасно и используется только для наглядности:

Запрос:

INSERT INTO encryption_test VALUES('aes-256-ofb no IV', encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212')),\
('aes-256-ofb no IV, different key', encrypt('aes-256-ofb', 'Secret', 'keykeykeykeykeykeykeykeykeykeyke')),\
('aes-256-ofb with IV', encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv')),\
('aes-256-cbc no IV', encrypt('aes-256-cbc', 'Secret', '12345678910121314151617181920212'));

Запрос:

SELECT comment, hex(secret) FROM encryption_test;

Результат:

┌─comment──────────────────────────┬─hex(secret)──────────────────────┐
│ aes-256-ofb no IV │ B4972BDC4459 │
│ aes-256-ofb no IV, different key │ 2FF57C092DC9 │
│ aes-256-ofb with IV │ 5E6CB398F653 │
│ aes-256-cbc no IV │ 1BC0629A92450D9E73A00E7D02CF4142 │
└──────────────────────────────────┴──────────────────────────────────┘

Пример в режиме -gcm:

Запрос:

INSERT INTO encryption_test VALUES('aes-256-gcm', encrypt('aes-256-gcm', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv')), \
('aes-256-gcm with AAD', encrypt('aes-256-gcm', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv', 'aad'));

SELECT comment, hex(secret) FROM encryption_test WHERE comment LIKE '%gcm%';

Результат:

┌─comment──────────────┬─hex(secret)──────────────────────────────────┐
│ aes-256-gcm │ A8A3CCBC6426CFEEB60E4EAE03D3E94204C1B09E0254 │
│ aes-256-gcm with AAD │ A8A3CCBC6426D9A1017A0A932322F1852260A4AD6837 │
└──────────────────────┴──────────────────────────────────────────────┘

aes_encrypt_mysql

Совместима с шифрованием mysql, результат может быть расшифрован функцией AES_DECRYPT.

При одинаковых входящих значениях зашифрованный текст будет совпадать с результатом, возвращаемым функцией encrypt. Однако если key или iv длиннее, чем должны быть, aes_encrypt_mysql будет работать аналогично функции aes_encrypt в MySQL: свернет ключ и проигнорирует лишнюю часть iv.

Функция поддерживает шифрофание данных следующими режимами:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-ofb, aes-192-ofb, aes-256-ofb

Синтаксис

aes_encrypt_mysql('mode', 'plaintext', 'key' [, iv])

Аргументы

  • mode — режим шифрования. String.
  • plaintext — текст, который будет зашифрован. String.
  • key — ключ шифрования. Если ключ длиннее, чем требует режим шифрования, производится специфичная для MySQL свертка ключа. String.
  • iv — инициализирующий вектор. Необязателен, учитываются только первые 16 байтов. String.

Возвращаемое значение

  • Бинарная зашифрованная строка. String.

Примеры

При одинаковых входящих значениях результаты шифрования у функций encrypt и aes_encrypt_mysql совпадают.

Запрос:

SELECT encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') = aes_encrypt_mysql('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') AS ciphertexts_equal;

Результат:

┌─ciphertexts_equal─┐
│ 1 │
└───────────────────┘

Функция encrypt генерирует исключение, если key или iv длиннее чем нужно:

Запрос:

SELECT encrypt('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123');

Результат:

Received exception from server (version 21.1.2):
Code: 36. DB::Exception: Received from localhost:9000. DB::Exception: Invalid key size: 33 expected 32: While processing encrypt('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123').

Однако функция aes_encrypt_mysql в аналогичном случае возвращает результат, который может быть обработан MySQL:

Запрос:

SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123')) AS ciphertext;

Результат:

┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘

Если передать iv еще длиннее, результат останется таким же:

Запрос:

SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456')) AS ciphertext

Результат:

┌─ciphertext───┐
│ 24E9E4966469 │
└──────────────┘

Это совпадает с результатом, возвращаемым MySQL при таких же входящих значениях:

mysql> SET  block_encryption_mode='aes-256-ofb';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT aes_encrypt('Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456') as ciphertext;
+------------------------+
| ciphertext |
+------------------------+
| 0x24E9E4966469 |
+------------------------+
1 row in set (0.00 sec)

decrypt

Функция расшифровывает зашифрованный текст и может работать в следующих режимах:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-cfb128
  • aes-128-ofb, aes-192-ofb, aes-256-ofb
  • aes-128-gcm, aes-192-gcm, aes-256-gcm
  • aes-128-ctr, aes-192-ctr, aes-256-ctr

Синтаксис

decrypt('mode', 'ciphertext', 'key' [, iv, aad])

Аргументы

  • mode — режим шифрования. String.
  • ciphertext — зашифрованный текст, который будет расшифрован. String.
  • key — ключ шифрования. String.
  • iv — инициализирующий вектор. Обязателен для -gcm режимов, для остальных режимов опциональный. String.
  • aad — дополнительные аутентифицированные данные. Текст не будет расшифрован, если это значение неверно. Работает только с -gcm режимами. Для остальных вызовет исключение. String.

Возвращаемое значение

  • Расшифрованная строка. String.

Примеры

Рассмотрим таблицу из примера для функции encrypt.

Запрос:

SELECT comment, hex(secret) FROM encryption_test;

Результат:

┌─comment──────────────┬─hex(secret)──────────────────────────────────┐
│ aes-256-gcm │ A8A3CCBC6426CFEEB60E4EAE03D3E94204C1B09E0254 │
│ aes-256-gcm with AAD │ A8A3CCBC6426D9A1017A0A932322F1852260A4AD6837 │
└──────────────────────┴──────────────────────────────────────────────┘
┌─comment──────────────────────────┬─hex(secret)──────────────────────┐
│ aes-256-ofb no IV │ B4972BDC4459 │
│ aes-256-ofb no IV, different key │ 2FF57C092DC9 │
│ aes-256-ofb with IV │ 5E6CB398F653 │
│ aes-256-cbc no IV │ 1BC0629A92450D9E73A00E7D02CF4142 │
└──────────────────────────────────┴──────────────────────────────────┘

Теперь попытаемся расшифровать эти данные:

Запрос:

SELECT comment, decrypt('aes-256-ofb', secret, '12345678910121314151617181920212') as plaintext FROM encryption_test;

Результат:

┌─comment──────────────┬─plaintext──┐
│ aes-256-gcm │ OQ�E
�t�7T�\���\� │
│ aes-256-gcm with AAD │ OQ�E
�\��si����;�o�� │
└──────────────────────┴────────────┘
┌─comment──────────────────────────┬─plaintext─┐
│ aes-256-ofb no IV │ Secret │
│ aes-256-ofb no IV, different key │ �4�
� │
│ aes-256-ofb with IV │ ���6�~ │
│aes-256-cbc no IV │ �2*4�h3c�4w��@
└──────────────────────────────────┴───────────┘

Обратите внимание, что только часть данных была расшифрована верно. Оставшаяся часть расшифрована некорректно, так как при шифровании использовались другие значения mode, key, или iv.

aes_decrypt_mysql

Совместима с шифрованием mysql и может расшифровать данные, зашифрованные функцией AES_ENCRYPT.

При одинаковых входящих значениях расшифрованный текст будет совпадать с результатом, возвращаемым функцией decrypt. Однако если key или iv длиннее, чем должны быть, aes_decrypt_mysql будет работать аналогично функции aes_decrypt в MySQL: свернет ключ и проигнорирует лишнюю часть iv.

Функция поддерживает расшифровку данных в следующих режимах:

  • aes-128-ecb, aes-192-ecb, aes-256-ecb
  • aes-128-cbc, aes-192-cbc, aes-256-cbc
  • aes-128-cfb128
  • aes-128-ofb, aes-192-ofb, aes-256-ofb

Синтаксис

aes_decrypt_mysql('mode', 'ciphertext', 'key' [, iv])

Аргументы

  • mode — режим шифрования. String.
  • ciphertext — зашифрованный текст, который будет расшифрован. String.
  • key — ключ шифрования. String.
  • iv — инициализирующий вектор. Необязателен. String.

Возвращаемое значение

  • Расшифрованная строка. String.

Примеры

Расшифруем данные, которые до этого были зашифрованы в MySQL:

mysql> SET  block_encryption_mode='aes-256-ofb';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT aes_encrypt('Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456') as ciphertext;
+------------------------+
| ciphertext |
+------------------------+
| 0x24E9E4966469 |
+------------------------+
1 row in set (0.00 sec)

Запрос:

SELECT aes_decrypt_mysql('aes-256-ofb', unhex('24E9E4966469'), '123456789101213141516171819202122', 'iviviviviviviviv123456') AS plaintext;

Результат:

┌─plaintext─┐
│ Secret │
└───────────┘