Encryption functions¶
These following functions implement encryption and decryption of data with the AES algorithm.
Key length depends on encryption mode. It is 16, 24, and 32 bytes long for -128-, -196-, and -256- modes respectively.
Initialization vector length is always 16 bytes. Bytes in excess of 16 are ignored.
encrypt¶
This function encrypts data using these modes:
- 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
Syntax¶
encrypt('mode', 'plaintext', 'key' [, iv, aad])
Arguments¶
mode: Encryption mode. String.plaintext: Text that need to be encrypted. String.key: Encryption key. String.iv: Initialization vector. Required for-gcmmodes, optional for others. String.aad: Additional authenticated data. It isn't encrypted, but it affects decryption. Works only in-gcmmodes, for others would throw an exception. String.
Returned value¶
- Ciphertext binary string. String.
Examples¶
Mock some data (please avoid storing the keys/ivs in the database as this undermines the whole concept of encryption), also storing 'hints' is unsafe too and used only for illustrative purposes:
Query:
SELECT comment, hex(secret) FROM
(
select c1 as comment, c2 as secret from 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'))
)
)
Result:
┌─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 │ └──────────────────────────────────┴──────────────────────────────────┘
Example with -gcm:
Query:
SELECT comment, hex(secret) FROM
(
select c1 as comment, c2 as secret from 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')),
('aes-256-gcm', encrypt('aes-256-gcm', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv')),
('aes-256-gcm with AAD', encrypt('aes-256-gcm', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv', 'aad'))
)
)
WHERE comment LIKE '%gcm%'
Result:
┌─comment──────────────┬─hex(secret)──────────────────────────────────┐ │ aes-256-gcm │ A8A3CCBC6426CFEEB60E4EAE03D3E94204C1B09E0254 │ │ aes-256-gcm with AAD │ A8A3CCBC6426D9A1017A0A932322F1852260A4AD6837 │ └──────────────────────┴──────────────────────────────────────────────┘
aes_encrypt_mysql¶
Compatible with mysql encryption and resulting ciphertext can be decrypted with AES_DECRYPT function.
Will produce the same ciphertext as encrypt on equal inputs. But when key or iv are longer than they should normally be, aes_encrypt_mysql will stick to what MySQL's aes_encrypt does: 'fold' key and ignore excess bits of iv.
Supported encryption modes:
- 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
Syntax¶
aes_encrypt_mysql('mode', 'plaintext', 'key' [, iv])
Arguments¶
mode: Encryption mode. String.plaintext: Text that needs to be encrypted. String.key: Encryption key. If key is longer than required by mode, MySQL-specific key folding is performed. String.iv: Initialization vector. Optional, only first 16 bytes are taken into account String.
Returned value¶
- Ciphertext binary string. String.
Examples¶
Given equal input encrypt and aes_encrypt_mysql produce the same ciphertext:
Query:
SELECT encrypt('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') = aes_encrypt_mysql('aes-256-ofb', 'Secret', '12345678910121314151617181920212', 'iviviviviviviviv') AS ciphertexts_equal
Result:
┌─ciphertexts_equal─┐ │ 1 │ └───────────────────┘
But encrypt fails when key or iv is longer than expected:
Query:
SELECT encrypt('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123')
Result:
Received exception from server (version 22.6.1):
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').
While aes_encrypt_mysql produces MySQL-compatible output:
Query:
SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123')) AS ciphertext
Result:
┌─ciphertext───┐ │ 24E9E4966469 │ └──────────────┘
Notice how supplying even longer IV produces the same result
Query:
SELECT hex(aes_encrypt_mysql('aes-256-ofb', 'Secret', '123456789101213141516171819202122', 'iviviviviviviviv123456')) AS ciphertext
Result:
┌─ciphertext───┐ │ 24E9E4966469 │ └──────────────┘
Which is binary equal to what MySQL produces on same inputs:
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¶
This function decrypts ciphertext into a plaintext using these modes:
- 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
Syntax¶
decrypt('mode', 'ciphertext', 'key' [, iv, aad])
Arguments¶
mode: Decryption mode. String.ciphertext: Encrypted text that needs to be decrypted. String.key: Decryption key. String.iv: Initialization vector. Required for-gcmmodes, Optional for others. String.aad: Additional authenticated data. Won't decrypt if this value is incorrect. Works only in-gcmmodes, for others would throw an exception. String.
Returned value¶
- Decrypted String. String.
tryDecrypt¶
Similar to decrypt, but returns NULL if decryption fails because of using the wrong key.
Examples¶
Create a table where user_id is the unique user id, encrypted is an encrypted string field, iv is an initial vector for decrypt/encrypt. Assume that users know their id and the key to decrypt the encrypted field:
Query:
SELECT
dt,
user_id,
tryDecrypt('aes-256-gcm', encrypted, 'keykeykeykeykeykeykeykeykeykey02', iv) AS value
FROM (
select c1::DateTime as dt, c2::UInt32 as user_id, c3::String as encrypted, c4::String as iv from values(
('2022-08-02 00:00:00', 1, encrypt('aes-256-gcm', 'value1', 'keykeykeykeykeykeykeykeykeykey01', 'iv1'), 'iv1'),
('2022-09-02 00:00:00', 2, encrypt('aes-256-gcm', 'value2', 'keykeykeykeykeykeykeykeykeykey02', 'iv2'), 'iv2'),
('2022-09-02 00:00:01', 3, encrypt('aes-256-gcm', 'value3', 'keykeykeykeykeykeykeykeykeykey03', 'iv3'), 'iv3')
)
)
ORDER BY user_id ASC
Result:
┌──────────────────dt─┬─user_id─┬─value──┐ │ 2022-08-02 00:00:00 │ 1 │ ᴺᵁᴸᴸ │ │ 2022-09-02 00:00:00 │ 2 │ value2 │ │ 2022-09-02 00:00:01 │ 3 │ ᴺᵁᴸᴸ │ └─────────────────────┴─────────┴────────┘
aes_decrypt_mysql¶
Compatible with mysql encryption and decrypts data encrypted with AES_ENCRYPT function.
Will produce same plaintext as decrypt on equal inputs. But when key or iv are longer than they should normally be, aes_decrypt_mysql will stick to what MySQL's aes_decrypt does: 'fold' key and ignore excess bits of IV.
Supported decryption modes:
- 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
Syntax¶
aes_decrypt_mysql('mode', 'ciphertext', 'key' [, iv])
Arguments¶
mode: Decryption mode. String.ciphertext: Encrypted text that needs to be decrypted. String.key: Decryption key. String.iv: Initialization vector. Optional. String.
Returned value¶
- Decrypted String. String.
Examples¶
Decrypt data you've previously encrypted with 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)
Query:
SELECT aes_decrypt_mysql('aes-256-ofb', unhex('24E9E4966469'), '123456789101213141516171819202122', 'iviviviviviviviv123456') AS plaintext
Result:
┌─plaintext─┐ │ Secret │ └───────────┘