# Encryption and Decryption Algorithms

This section explains the specific algorithms that are used when values 1 through 9 are specified for the `ENCRYPT_KS` and `DECRYPT_KS` functions. Values 4 through 9 only are supported for `ENCRYPTED WITH` column constraints in `CREATE TABLE` statements, using the same algorithms.

Function Parameter Algorithm Output Length (Encryption) Output Length (Decryption)
1 Initialize AES with a 128-bit key and encrypt (or decrypt) using Output Feedback Mode (OFB). `floor((n1 * 8 + 5) / 6)` `floor((n1 * 6) / 8))`
2 Initialize AES with a 192-bit key and encrypt (or decrypt) using OFB. `floor((n1 * 8 + 5) / 6)` `floor((n1 * 6) / 8))`
3 Initialize AES with a 256-bit key and encrypt (or decrypt) using OFB. `floor((n1 * 8 + 5) / 6)` `floor((n1 * 6) / 8))`
4 Use 128-bit key deterministic encryption (or deterministic decryption). `ceil((17 + n1) / 3) * 4` `(floor(n1 / 4) * 3) - 17`
5 Use 192-bit key deterministic encryption (or deterministic decryption). `ceil((25 + n1) / 3) * 4` `(floor(n1 / 4) * 3) - 25`
6 Use 256-bit key deterministic encryption (or deterministic decryption). `ceil((33 + n1) / 3) * 4` `(floor(n1 / 4) * 3) - 33`
7 Use 128-bit key randomized encryption (or randomized decryption). `ceil((17 + n1) / 3) * 4` `(floor(n1 / 4) * 3) - 17`
8 Use 192-bit key randomized encryption (or randomized decryption). `ceil((25 + n1) / 3) * 4` `(floor(n1 / 4) * 3) - 25`
9 Use 256-bit key randomized encryption (or randomized decryption). `ceil((33 + n1) / 3) * 4` `(floor(n1 / 4) * 3) - 33`

## Randomized Encryption

The algorithm for randomized (non-deterministic) encryption follows these steps:
1. Accept (binary) input string `plaintext` with length `plaintext_length` bytes.
2. Accept (binary) input key with length `key_length` bytes.
3. Accept (integer) input `aes_keybits` (must be 128, 192, or 256).
4. Reuse/fold key to `aes_keybits`. The actual size of the key required depends on the algorithm selected. The actual size of the initialization vector for modes 4 to 9 is 128 bits.
• When the input `key` or `ivec` is shorter than expected, reuse the input until the required size is reached.
• When the input `key` or `ivec` is longer than expected, fold the extra input with the required input via `XOR`.
5. Generate a cryptographically random salt with `aes_keybits` (likely generated via Fortuna).
6. ```ciphertext = ofb_aes(plaintext, key = (key XOR salt), iv = (salt >> (aes_keybits - 128))```
7. `ciphertext_length = plaintext_length`
8. ```outputtext = version (1 byte) + salt (aes_keybits/8) + ciphertext (ciphertext_length bytes)```
9. ```outputtext_length = 1 + (aes_keybits/8) + ciphertext_length```
Note:
• This encryption algorithm is specifically designed to be secure against any kind of chosen plain-text attacks (including dictionary-based attacks for low-cardinality data sets).
• This algorithm is also resistant to length-extension attacks; that is, an attacker with encrypt access cannot pad a chosen (binary) string to an already encrypted value.
• Use an HMAC on the `outputtext` separately if you need to protect against random padding.
• `ciphertext_length` mirrors `plaintext_length`, and therefore leaks information about the input. For example, `ciphertext` for `'m'` will be indistinguishable (in length and randomness) from `ciphertext` for `'f'`; however, `ciphertext_length` for `'male'` will be different from `ciphertext_length` for `'female'`. To guard against this leakage, pad all input to the same length.

## Randomized Decryption

The algorithm for randomized (non-deterministic) decryption follows these steps:
1. Accept (binary) input string `outputtext` with length `outputtext_length` bytes.
2. Accept (binary) input key with length `key_length` bytes.
3. Accept (integer) input `aes_keybits` (must 128, 192, or 256).
4. Reuse/fold key to `aes_keybits`. The actual size of the key required depends on the algorithm selected. The actual size of the initialization vector for modes 4 to 9 is 128 bits.
• When the input `key` or `ivec` is shorter than expected, reuse the input until the required size is reached.
• When the input `key` or `ivec` is longer than expected, fold the extra input with the required input via `XOR`.
5. `version = outputtext[0:0]`
6. `salt = outputtext[1:(aes_keybits/8)]`
7. ```ciphertext = outputtext[(aes_keybits/8):(outputtext_length-1)]```
8. ```plaintext = ofb_aes(ciphertext, key = (key XOR salt), iv = (salt >> (aes_keybits - 128))```
9. ```plaintext_length = outputtext_length - (1 + (aes_keybits/8))```
Note:
• This decryption algorithm is not susceptible to padding-oracle attacks.
• OFB enables decryption in a stream-cipher mode instead of requiring PKCS-like padding.
• An attacker who has decrypt access but not encrypt access may be able to encrypt chosen plain texts. This may be a problem if a user erroneously relies on an encryption system for message-authentication; use a proper HMAC if needed to prevent message forgery.

## Deterministic Encryption

The algorithm is the same as in randomized encryption, except for the choice of `salt` in step 5:
``salt = hmac_sha256(key, plaintext) >> (256 - aes_keybits);``
Note:
• Identical `plaintext` strings encrypt to identical `outputtext` strings when you use the same `key`; this method enables equality comparison.
• The same `plaintext` value encrypted with two different keys generates two different `outputtext` values.

## Deterministic Decryption

The algorithm for deterministic decryption works exactly the same as the algorithm for randomized decryption.

Note:
• padding-oracle attacks are not possible.
• Given that deterministic decryption uses an `hmac_sha256` instead of `sha256`, it is possible to detect and prevent random length extensions. However, for compatibility with randomized encryption, Yellowbrick decryption instead returns an undefined result.

## A Warning about "Symmetric" Algorithms

Encryption algorithms `1`, `2`, and `3` are considered "symmetric." Users need to be careful about choosing these algorithms if the default initialization vector (IV) is being used, if the IV is well-known, or if the IV may have been leaked. In these scenarios, roles who have `ENCRYPT` but not `DECRYPT` access may be able to decipher strings by reverse engineering the bit-stream that was used to protect those strings.

For example, assume that encryption key `k0` and role `r0` exist in your system, that `r0` is neither a superuser nor the owner of `k0`, and that `r0` has been granted `ENCRYPT` but not `DECRYPT` access on `k0`.

In turn, `r0` can run a query where:
``cipher-text = encrypt(plain-text, k0, {1 | 2 | 3}, iv)``

Although `r0` cannot run an equivalent `DECRYPT` query, the following property holds true for binary data:

``plain-text = encrypt(encrypt(plain-text, k0, {1 | 2 | 3}, iv), k0, {1 | 2 | 3}, iv)``

Therefore, if `r0` happens to know the `iv` in use, `r0` can recover the plain-text from the cipher-text by reverse-engineering the bit-stream used to protect the plain-text string.