Функции шифрования
Данные функции реализуют шифрование и расшифровку данных с помощью 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 │
└───────────┘