# 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

- Accept (binary) input string
`plaintext`

with length`plaintext_length`

bytes. - Accept (binary) input key with length
`key_length`

bytes. - Accept (integer) input
`aes_keybits`

(must be 128, 192, or 256). - 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`

.

- When the input
- Generate a cryptographically random salt with
`aes_keybits`

(likely generated via Fortuna). `ciphertext = ofb_aes(plaintext, key = (key XOR salt), iv = (salt >> (aes_keybits - 128))`

`ciphertext_length = plaintext_length`

`outputtext = version (1 byte) + salt (aes_keybits/8) + ciphertext (ciphertext_length bytes)`

`outputtext_length = 1 + (aes_keybits/8) + ciphertext_length`

- 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

- Accept (binary) input string
`outputtext`

with length`outputtext_length`

bytes. - Accept (binary) input key with length
`key_length`

bytes. - Accept (integer) input
`aes_keybits`

(must 128, 192, or 256). - 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`

.

- When the input
`version = outputtext[0:0]`

`salt = outputtext[1:(aes_keybits/8)]`

`ciphertext = outputtext[(aes_keybits/8):(outputtext_length-1)]`

`plaintext = ofb_aes(ciphertext, key = (key XOR salt), iv = (salt >> (aes_keybits - 128))`

`plaintext_length = outputtext_length - (1 + (aes_keybits/8))`

- 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

`salt`

in step 5:
`salt = hmac_sha256(key, plaintext) >> (256 - aes_keybits);`

- 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.

*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`

.

`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.