AES harness¶
Test encryption¶
To test a function that encrypts with AES, the harness function must:
follow the naming convention;
conform to the function signature.
Naming convention¶
CC_AES_<mode>_encrypt
Where mode
is one of: ECB
, CBC
, CBCPKCS7
, CTR
, CFB8
, CFB128
.
This tests all key lengths. A specific one can be indicated:
CC_AES_<mode>_<length>_encrypt
Where length
is one of 128
, 192
, or 256
.
Function signature¶
- int AES_encrypt(
- uint8_t *ciphertext,
- size_t ciphertext_size,
- const uint8_t *plaintext,
- size_t plaintext_size,
- const uint8_t *key,
- size_t key_size,
- const uint8_t *iv,
- size_t iv_size,
Encrypts a plaintext with AES.
- Parameters:
ciphertext – [Out] An allocated buffer to return the resulting ciphertext.
ciphertext_size – [In] The size of
ciphertext
in bytes.plaintext – [In] The plaintext to encrypt.
plaintext_size – [In] The size of
plaintext
in bytes.key – [In] The symmetric key to use.
key_size – [In] The size of
key
in bytes. Passed even when specifying the key size.iv – [In] The IV to use. Not used for ECB mode.
iv_size – [In] The size of
iv
in bytes. 0 if the IV is not used.
- Returns:
A status value.
- Return values:
1 – Operation successful.
0 – An error occurred.
Example¶
#include <openssl/evp.h>
// Define a generic function to use for all modes.
int encrypt(const EVP_CIPHER *cipher, uint8_t *ciphertext,
size_t ciphertext_size, const uint8_t *plaintext,
size_t plaintext_size, const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size);
int CC_AES_ECB_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return encrypt(EVP_aes_256_ecb(), ciphertext, ciphertext_size, plaintext,
plaintext_size, key, key_size, iv, iv_size);
}
int CC_AES_CBC_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return encrypt(EVP_aes_256_cbc(), ciphertext, ciphertext_size, plaintext,
plaintext_size, key, key_size, iv, iv_size);
}
int CC_AES_CTR_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return encrypt(EVP_aes_256_ctr(), ciphertext, ciphertext_size, plaintext,
plaintext_size, key, key_size, iv, iv_size);
}
int CC_AES_CFB8_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return encrypt(EVP_aes_256_cfb8(), ciphertext, ciphertext_size, plaintext,
plaintext_size, key, key_size, iv, iv_size);
}
int CC_AES_CFB128_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return encrypt(EVP_aes_256_cfb128(), ciphertext, ciphertext_size, plaintext,
plaintext_size, key, key_size, iv, iv_size);
}
// CBC-PKCS7 uses padding, unlike the other modes.
int CC_AES_CBCPKCS7_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len = 0;
if (!ctx)
goto error;
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
goto error;
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_size))
goto error;
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
goto error;
EVP_CIPHER_CTX_free(ctx);
return 1;
error:
EVP_CIPHER_CTX_free(ctx);
return 0;
}
int encrypt(const EVP_CIPHER *cipher, uint8_t *ciphertext,
size_t ciphertext_size, const uint8_t *plaintext,
size_t plaintext_size, const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len = 0;
if (!ctx)
goto error;
// Disable padding, as the test vectors are without it.
EVP_CIPHER_CTX_set_padding(ctx, 0);
if (1 != EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv))
goto error;
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_size))
goto error;
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
goto error;
EVP_CIPHER_CTX_free(ctx);
return 1;
error:
EVP_CIPHER_CTX_free(ctx);
return 0;
}
Compile with:
gcc -fPIC -static -o AES_openssl_encrypt.so AES_openssl_encrypt.c -lssl -lcrypto
Then test with:
crypto-condor-cli test harness AES_openssl_encrypt.so
Test authenticated encryption¶
To test a function that encrypts with an AEAD mode, the harness function must:
follow the naming convention;
conform to the function signature.
Naming convention¶
CC_AES_<mode>_encrypt
Where mode
is one of: CCM
, GCM
.
This tests all key lengths. A specific one can be indicated:
CC_AES_<mode>_<length>_encrypt
Where length
is one of 128
, 192
, or 256
.
Function signature¶
- int AES_encrypt_aead(
- uint8_t *ciphertext,
- size_t ciphertext_size,
- uint8_t *mac,
- size_t mac_size,
- const uint8_t *plaintext,
- size_t plaintext_size,
- const uint8_t *key,
- size_t key_size,
- const uint8_t *iv,
- size_t iv_size,
- const uint8_t *aad,
- size_t aad_size,
Encrypts a plaintext with AES and an AEAD mode of operation.
- Parameters:
ciphertext – [Out] An allocated buffer to return the resulting ciphertext.
ciphertext_size – [In] The size of
ciphertext
in bytes.mac – [Out] An allocated buffer to return the resulting MAC tag.
mac_size – [In] The size of
mac
in bytes.plaintext – [In] The plaintext to encrypt.
plaintext_size – [In] The size of
plaintext
in bytes.key – [In] The symmetric key to use.
key_size – [In] The size of
key
in bytes. Passed even when specifying the key size.iv – [In] The IV to use. Not used for ECB mode.
iv_size – [In] The size of
iv
in bytes. 0 if the IV is not used.
- Returns:
A status value.
- Return values:
1 – Operation successful.
0 – An error occurred.
Example¶
#include <openssl/evp.h>
int CC_AES_GCM_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
uint8_t *mac, size_t mac_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *nonce, size_t nonce_size,
const uint8_t *aad, size_t aad_size) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len;
if (!ctx)
goto error;
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
goto error;
if (1 !=
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, nonce_size, NULL)) {
fprintf(stderr, "Failed to set IV len\n");
goto error;
}
if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce))
goto error;
if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_size))
goto error;
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_size))
goto error;
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
goto error;
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, mac_size, mac))
goto error;
EVP_CIPHER_CTX_free(ctx);
return 1;
error:
EVP_CIPHER_CTX_free(ctx);
return 0;
}
int CC_AES_CCM_256_encrypt(uint8_t *ciphertext, size_t ciphertext_size,
uint8_t *mac, size_t mac_size,
const uint8_t *plaintext, size_t plaintext_size,
const uint8_t *key, size_t key_size,
const uint8_t *nonce, size_t nonce_size,
const uint8_t *aad, size_t aad_size) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len;
if (!ctx)
goto error;
if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
goto error;
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, nonce_size, NULL))
goto error;
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, mac_size, NULL);
if (1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce))
goto error;
// Provide total plaintext length.
if (1 != EVP_EncryptUpdate(ctx, NULL, &len, NULL, plaintext_size))
goto error;
// Provide any AAD data.
if (aad_size > 0) {
if (1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_size))
goto error;
}
if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_size))
goto error;
if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
goto error;
if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, mac_size, mac))
goto error;
EVP_CIPHER_CTX_free(ctx);
return 1;
error:
EVP_CIPHER_CTX_free(ctx);
return 0;
}
Compile with:
gcc -fPIC -static -o AES_openssl_encrypt_aead.so AES_openssl_encrypt_aead.c -lssl -lcrypto
Then test with:
crypto-condor-cli test harness AES_openssl_encrypt_aead.so
Test decryption¶
To test a function that decrypts with AES, the harness function must:
follow the naming convention;
conform to the function signature.
Naming convention¶
CC_AES_<mode>_decrypt
Where mode
is one of: CCM
, GCM
.
This tests all key lengths. A specific one can be indicated:
CC_AES_<mode>_<length>_decrypt
Where length
is one of 128
, 192
, or 256
.
Function signature¶
- int AES_decrypt(
- uint8_t *plaintext,
- size_t plaintext_size,
- const uint8_t *ciphertext,
- size_t ciphertext_size,
- const uint8_t *key,
- size_t key_size,
- const uint8_t *iv,
- size_t iv_size,
Decrypts a ciphertext with AES.
- Parameters:
plaintext – [Out] An allocated buffer to return the resulting plaintext.
plaintext_size – [In] The size of
plaintext
in bytes.ciphertext – [In] The ciphertext to decrypt.
ciphertext_size – [In] The size of
ciphertext
in bytes.key – [In] The symmetric key to use.
key_size – [In] The size of
key
in bytes. Passed even when specifying the key size.iv – [In] The IV to use. Not used for ECB mode.
iv_size – [In] The size of
iv
in bytes. 0 if the IV is not used.
- Returns:
The actual size of the (unpadded) plaintext, or -1 if an error occurred.
Example¶
#include <openssl/evp.h>
int decrypt(const EVP_CIPHER *cipher, uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size, const uint8_t *iv,
size_t iv_size);
int CC_AES_ECB_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return decrypt(EVP_aes_256_ecb(), plaintext, plaintext_size, ciphertext,
ciphertext_size, key, key_size, iv, iv_size);
}
int CC_AES_CBC_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return decrypt(EVP_aes_256_cbc(), plaintext, plaintext_size, ciphertext,
ciphertext_size, key, key_size, iv, iv_size);
}
int CC_AES_CTR_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return decrypt(EVP_aes_256_ctr(), plaintext, plaintext_size, ciphertext,
ciphertext_size, key, key_size, iv, iv_size);
}
int CC_AES_CFB8_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return decrypt(EVP_aes_256_cfb8(), plaintext, plaintext_size, ciphertext,
ciphertext_size, key, key_size, iv, iv_size);
}
int CC_AES_CFB128_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
return decrypt(EVP_aes_256_cfb128(), plaintext, plaintext_size, ciphertext,
ciphertext_size, key, key_size, iv, iv_size);
}
int CC_AES_CBCPKCS7_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size) {
int pt_len = 0, len = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx)
goto error;
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
goto error;
if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_size))
goto error;
pt_len += len;
if (!EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
goto error;
pt_len += len;
EVP_CIPHER_CTX_free(ctx);
return pt_len;
error:
EVP_CIPHER_CTX_free(ctx);
return -1;
}
int decrypt(const EVP_CIPHER *cipher, uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *key, size_t key_size, const uint8_t *iv,
size_t iv_size) {
int len = 0, pt_len = 0;
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
if (!ctx)
goto error;
if (1 != EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv))
goto error;
EVP_CIPHER_CTX_set_padding(ctx, 0);
if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_size))
goto error;
pt_len += len;
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
goto error;
pt_len += len;
EVP_CIPHER_CTX_free(ctx);
return pt_len;
error:
EVP_CIPHER_CTX_free(ctx);
return -1;
}
Compile with:
gcc -fPIC -static -o AES_openssl_decrypt.so AES_openssl_decrypt.c -lssl -lcrypto
Then test with:
crypto-condor-cli test harness AES_openssl_decrypt.so
Test authenticated decryption¶
To test a function that decrypts with an AEAD mode, the harness function must:
follow the naming convention;
conform to the function signature.
Naming convention¶
CC_AES_<mode>_decrypt
Where mode
is one of: CCM
, GCM
.
This tests all key lengths. A specific one can be indicated:
CC_AES_<mode>_<length>_decrypt
Where length
is one of 128
, 192
, or 256
.
Function signature¶
- int AES_decrypt_aead(
- uint8_t *plaintext,
- size_t plaintext_size,
- const uint8_t *ciphertext,
- size_t ciphertext_size,
- const uint8_t *mac,
- size_t mac_size,
- const uint8_t *key,
- size_t key_size,
- const uint8_t *iv,
- size_t iv_size,
- const uint8_t *aad,
- size_t aad_size,
Decrypts a ciphertext with AES and an AEAD mode of operation.
- Parameters:
plaintext – [Out] An allocated buffer to return the resulting plaintext.
plaintext_size – [In] The size of
plaintext
in bytes.ciphertext – [In] The ciphertext to decrypt.
ciphertext_size – [In] The size of
ciphertext
in bytes.mac – [In] The MAC tag to verify.
mac_size – [In] The size of
mac
in bytes.key – [In] The symmetric key to use.
key_size – [In] The size of
key
in bytes. Passed even when specifying the key size.iv – [In] The IV to use. Not used for ECB mode.
iv_size – [In] The size of
iv
in bytes. 0 if the IV is not used.
- Returns:
A status value.
- Return values:
1 – Operation successful.
0 – An error occurred.
-1 – The MAC tag is invalid.
Example¶
#include <openssl/evp.h>
int CC_AES_GCM_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *mac, size_t mac_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size,
const uint8_t *aad, size_t aad_size) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len = 0;
if (!ctx)
goto error;
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL))
goto error;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_size, NULL))
goto error;
if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
goto error;
if (aad_size > 0)
if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_size))
goto error;
if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_size))
goto error;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, mac_size, (void *)mac))
goto error;
if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
EVP_CIPHER_CTX_free(ctx);
return 1;
error:
EVP_CIPHER_CTX_free(ctx);
return 0;
}
int CC_AES_CCM_256_decrypt(uint8_t *plaintext, size_t plaintext_size,
const uint8_t *ciphertext, size_t ciphertext_size,
const uint8_t *mac, size_t mac_size,
const uint8_t *key, size_t key_size,
const uint8_t *iv, size_t iv_size,
const uint8_t *aad, size_t aad_size) {
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
int len = 0;
if (!ctx)
goto error;
if (!EVP_DecryptInit_ex(ctx, EVP_aes_256_ccm(), NULL, NULL, NULL))
goto error;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, iv_size, NULL))
goto error;
if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, mac_size, (void *)mac))
goto error;
if (!EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv))
goto error;
// Provide total ciphertext length.
if (!EVP_DecryptUpdate(ctx, NULL, &len, NULL, ciphertext_size))
goto error;
if (aad_size > 0)
if (!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_size))
goto error;
if (1 !=
EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_size)) {
EVP_CIPHER_CTX_free(ctx);
return -1;
}
EVP_CIPHER_CTX_free(ctx);
return 1;
error:
EVP_CIPHER_CTX_free(ctx);
return 0;
}
Compile with:
gcc -fPIC -static -o AES_openssl_decrypt_aead.so AES_openssl_decrypt_aead.c -lssl -lcrypto
Then test with:
crypto-condor-cli test harness AES_openssl_decrypt_aead.so