Available in all subroutines.

Symmetric key encryption.

The cipher parameter specifies both the cipher name (AES) and the key size (128-bit, 192-bit, 256-bit). The available ciphers are: aes128, aes192, aes256.

The mode parameter specifies the mode of operation for the given cipher. ECB, CFB, and OFB modes are not provided, but are discussed here for context. The available modes for AES are: cbc, ctr.

The padding parameter specifies padding for block ciphers. The available padding values are pkcs7 and nopad for no padding. When using ctr mode, the padding must be set to nopad.

When using CBC or ECB mode with padding set to nopad, plaintext must decode to raw data exactly equal in length to the block size for the given cipher.

The key, Initialization Vector (IV), plaintext, and ciphertext are all hex encoded strings. Hex values are case insensitive, and do not have a leading 0x prefix. For block ciphers, the IV must decode to raw data of exactly equal in length to the block size for the given cipher.

For modes that do not use an IV, the iv parameter is passed either a not set value or an empty string. AES CBC and CTR modes require the iv parameter to be set.

For ciphers with a fixed key length, the key must decode to raw data of a size exactly equal in length to the key size for the given cipher.


CBC and ECB modes require that input exactly divides into a sequence of fixed-size blocks. This is ensured either by passing in data of the appropriate length, or by padding it to meet the size requirement. CTR, CFB and OFB modes do not have this requirement, so no padding is applied for those modes.

The parameter pkcs7 represents PKCS#7 as specified by RFC 5652 §6.3. This is identical to PKCS#5, except that PKCS#5 is only defined for 64-bit block sizes and PKCS#7 is defined for any block size.

Block size depends on the cipher in use. AES has a block size of 16.

Padding will add the smallest number of bytes required to reach the next block size. This is always one byte at minimum. For example, an empty string will be padded to a single block, and data exactly the size of a single block will be padded to two blocks.

Key generation

The key_hex and iv_hex parameters are not verbatim passwords. However these may be derived from passwords using a key derivation function such as PBKDF2 (specified by RFC 2898 §5.2).

An example showing using the OpenSSL command line tool to derive a 256-bit key and IV (both in hex) suitable for AES CBC:

$ openssl enc -nosalt -aes-256-cbc -pbkdf2 -k example -P
iv =F2F8B61408F67638B6FBEEB2348F0B5B

For ctr mode, the iv parameter serves as the CTR counter rather than as an IV. The counter is subject to constraints in order to behave securely. In particular a given counter value and key should not be reused in combination to encrypt two plaintext data sets.


If the requirements for the given cipher and mode are not met, or if the hex-encoded arguments are not valid hex, then fastly.error will be set to EINVAL.

If the wrong key or IV are used when decrypting with AES CBC, then fastly.error will be set to EBADDECRYPT.

Decrypting with AES CTR cannot produce EBADDECRYPT. For AES CTR, decryption is the same as encrypting. Decrypting with the wrong key will still produce a plaintext result, but it will contain meaningless data.


An example from NIST Special Publication 800-38A F.2.5, illustrating encrypting and decrypting an example vector using 256-bit AES CBC:

declare local var.key STRING;
declare local var.iv STRING;
declare local var.plaintext STRING; # hex encoded input
declare local var.ciphertext STRING; # hex encoded output
# NIST sample vector data
set var.key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; # 256-bit
set var.iv = "000102030405060708090a0b0c0d0e0f"; # 16 bytes
set var.plaintext = "6bc1bee22e409f96e93d7e117393172a";
unset fastly.error;
set var.ciphertext = crypto.encrypt_hex(aes256, cbc, nopad,
var.key, var.iv, var.plaintext);
# returns the 16-byte ciphertext "f58c4c04d6e5f1ba779eabfb5f7bfbd6"
if (fastly.error) {
error 503;
set var.plaintext = crypto.decrypt_hex(aes256, cbc, nopad,
var.key, var.iv, var.ciphertext);
if (fastly.error == "EBADDECRYPT") {
error 403 "Wrong key";
} else if (fastly.error) {
error 503;

The same ciphertext may be confirmed by using the OpenSSL command line tool:

$ echo -n 6bc1bee22e409f96e93d7e117393172a \
| xxd -r -p \
| openssl enc -nosalt -nopad -aes-256-cbc \
-K 603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4 \
-iv 000102030405060708090a0b0c0d0e0f \
| xxd -p