Skip to content

Commit

Permalink
[aes/model] Add AES-GCM to AES models
Browse files Browse the repository at this point in the history
This commit adds support for the AES-GCM mode to the
AES models. For the comparison, test vectors specified
by NIST are used.

Signed-off-by: Pascal Nasahl <[email protected]>
  • Loading branch information
nasahlpa authored and vogelpi committed Oct 13, 2024
1 parent d6fb88f commit fe3c200
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 19 deletions.
4 changes: 2 additions & 2 deletions hw/ip/aes/model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ In addition, this directory also contains two example applications.
2. `aes_modes`:
- Shows how to interface the OpenSSL/BoringSSL interface functions.
- Checks the output of BoringSSL/OpenSSL versus expected results.
- Supports ECB, CBC, CTR modes.
- Supports ECB, CBC, CTR, GCM modes.

How to build and run the examples
---------------------------------
Expand Down Expand Up @@ -54,4 +54,4 @@ Details of the model
- `aes_example.c/h`: Contains the first example application including test input
and expected output for ECB mode.
- `aes_modes.c/h`: Contains the second example application including test input
and expected output for ECB, CBC, CTR modes.
and expected output for ECB, CBC, CTR, GCM modes.
4 changes: 2 additions & 2 deletions hw/ip/aes/model/aes_example.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ int main(int argc, char *argv[]) {

// check state vs BoringSSL/OpenSSL
cipher_text_len = crypto_encrypt(cipher_text, iv, plain_text, 16, key,
key_len, kCryptoAesEcb);
key_len, kCryptoAesEcb, NULL, 0, NULL, 0);
if (!check_block(state, cipher_text, 0)) {
printf("SUCCESS: state matches %s cipher text\n", crypto_lib);
} else {
Expand Down Expand Up @@ -334,7 +334,7 @@ int main(int argc, char *argv[]) {

// check state vs BoringSSL/OpenSSL
crypto_decrypt(decrypted_text, iv, cipher_text, cipher_text_len, key, key_len,
kCryptoAesEcb);
kCryptoAesEcb, NULL, 0, NULL, 0);
if (!check_block(state, decrypted_text, 0)) {
printf("SUCCESS: state matches %s decrypted text\n", crypto_lib);
} else {
Expand Down
90 changes: 80 additions & 10 deletions hw/ip/aes/model/aes_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ static int crypto_compare(const unsigned char *cipher_text,
const unsigned char *iv,
const unsigned char *plain_text, int len,
const unsigned char *key, int key_len,
crypto_mode_t mode) {
crypto_mode_t mode, const unsigned char *aad,
int aad_len, const unsigned char *tag, int tag_len) {
const unsigned char *data_in;
const unsigned char *aad_in;
int ret_len;
int ret_len_exp = len;

Expand All @@ -50,8 +52,17 @@ static int crypto_compare(const unsigned char *cipher_text,
return 1;
}
data_in = plain_text;
aad_in = aad;

ret_len = crypto_encrypt(data_out, iv, data_in, len, key, key_len, mode);
unsigned char *tag_out =
(unsigned char *)malloc(tag_len * sizeof(unsigned char));
if (tag_out == NULL) {
printf("ERROR: malloc() failed\n");
return 1;
}

ret_len = crypto_encrypt(data_out, iv, data_in, len, key, key_len, mode,
aad_in, aad_len, tag_out, tag_len);
if (ret_len != ret_len_exp) {
printf("ERROR: ret_len = %i, expected %i. Aborting now\n", ret_len,
ret_len_exp);
Expand All @@ -76,6 +87,22 @@ static int crypto_compare(const unsigned char *cipher_text,
}
}

if (mode == kCryptoAesGcm) {
for (int j = 0; j < tag_len / 16; ++j) {
if (!check_block(&tag_out[j * 16], &tag[j * 16], 1)) {
printf("SUCCESS: %s tag output matches NIST example tag\n", crypto_lib);
} else {
printf("ERROR: %s tag output does not match NIST example tag\n",
crypto_lib);
printf("Tag output: \t");
aes_print_block(&tag_out[j * 16], 16);
printf("Expected tag: \t");
aes_print_block(&tag[j * 16], 16);
return 1;
}
}
}

// Dec
unsigned char *data_in_dec =
(unsigned char *)malloc(ret_len_exp * sizeof(unsigned char));
Expand All @@ -86,9 +113,11 @@ static int crypto_compare(const unsigned char *cipher_text,
for (int j = 0; j < ret_len; ++j) {
data_in_dec[j] = data_out[j];
}
unsigned char *tag_in;
tag_in = tag_out;

ret_len =
crypto_decrypt(data_out, iv, data_in_dec, ret_len, key, key_len, mode);
ret_len = crypto_decrypt(data_out, iv, data_in_dec, ret_len, key, key_len,
mode, aad_in, aad_len, tag_in, tag_len);
if (ret_len != len) {
printf("ERROR: ret_len = %i, expected %i. Aborting now\n", ret_len, len);
return 1;
Expand Down Expand Up @@ -119,12 +148,16 @@ static int crypto_compare(const unsigned char *cipher_text,
}

int main(int argc, char *argv[]) {
const int len = 64;
int len = 64;
int key_len;
int tag_len = 0;
int aad_len = 0;
crypto_mode_t mode;
const unsigned char *iv;
const unsigned char *key;
const unsigned char *cipher_text;
const unsigned char *aad = NULL;
const unsigned char *tag = NULL;

/////////
// ECB //
Expand All @@ -151,7 +184,7 @@ int main(int argc, char *argv[]) {
}

if (crypto_compare(cipher_text, iv, kAesModesPlainText, len, key, key_len,
mode)) {
mode, aad, aad_len, tag, tag_len)) {
return 1;
}
}
Expand Down Expand Up @@ -181,7 +214,7 @@ int main(int argc, char *argv[]) {
}

if (crypto_compare(cipher_text, iv, kAesModesPlainText, len, key, key_len,
mode)) {
mode, aad, aad_len, tag, tag_len)) {
return 1;
}
}
Expand Down Expand Up @@ -212,7 +245,7 @@ int main(int argc, char *argv[]) {
}

if (crypto_compare(cipher_text, iv, kAesModesPlainText, len, key, key_len,
mode)) {
mode, aad, aad_len, tag, tag_len)) {
return 1;
}
}
Expand Down Expand Up @@ -242,7 +275,7 @@ int main(int argc, char *argv[]) {
}

if (crypto_compare(cipher_text, iv, kAesModesPlainText, len, key, key_len,
mode)) {
mode, aad, aad_len, tag, tag_len)) {
return 1;
}
}
Expand Down Expand Up @@ -272,7 +305,44 @@ int main(int argc, char *argv[]) {
}

if (crypto_compare(cipher_text, iv, kAesModesPlainText, len, key, key_len,
mode)) {
mode, aad, aad_len, tag, tag_len)) {
return 1;
}
}

/////////
// GCM //
/////////
iv = kAesModesIvGcm;
mode = kCryptoAesGcm;
len = 60;
tag_len = 16;
aad_len = 20;
aad = kAesModesAadGcm;

for (int i = 0; i < 3; ++i) {
if (i == 0) {
printf("GCM AES-128\n");
key_len = 16;
key = kAesModesGcmKey128;
cipher_text = kAesModesCipherTextGcm128;
tag = kAesModesTagGcm128;
} else if (i == 1) {
printf("GCM AES-192\n");
key_len = 24;
key = kAesModesGcmKey192;
cipher_text = kAesModesCipherTextGcm192;
tag = kAesModesTagGcm192;
} else { // i==2
printf("GCM AES-256\n");
key_len = 32;
key = kAesModesGcmKey256;
cipher_text = kAesModesCipherTextGcm256;
tag = kAesModesTagGcm256;
}

if (crypto_compare(cipher_text, iv, kAesModesPlainTextGcm, len, key,
key_len, mode, aad, aad_len, tag, tag_len)) {
return 1;
}
}
Expand Down
65 changes: 65 additions & 0 deletions hw/ip/aes/model/aes_modes.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,69 @@ static const unsigned char kAesModesCipherTextCtr256[64] = {
0x2d, 0x84, 0x98, 0x8d, 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad,
0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6};

// The examples below are extracted from the NIST Publication "The
// Galois/Counter Mode of Operation (GCM)" available at
// https://csrc.nist.rip/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-spec.pdf

// GCM
static const unsigned char kAesModesIvGcm[12] = {
0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, 0xde, 0xca, 0xf8, 0x88};

static const unsigned char kAesModesAadGcm[20] = {
0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed,
0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2};

static const unsigned char kAesModesGcmKey128[16] = {
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c,
0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08};

static const unsigned char kAesModesGcmKey192[24] = {
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94,
0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c};

static const unsigned char kAesModesGcmKey256[32] = {
0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, 0x6d, 0x6a, 0x8f,
0x94, 0x67, 0x30, 0x83, 0x08, 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65,
0x73, 0x1c, 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08};

static const unsigned char kAesModesPlainTextGcm[60] = {
0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, 0xa5, 0x59, 0x09, 0xc5,
0xaf, 0xf5, 0x26, 0x9a, 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda,
0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, 0x1c, 0x3c, 0x0c, 0x95,
0x95, 0x68, 0x09, 0x53, 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25,
0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, 0xba, 0x63, 0x7b, 0x39};

static const unsigned char kAesModesCipherTextGcm128[60] = {
0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, 0x4b, 0x72, 0x21, 0xb7,
0x84, 0xd0, 0xd4, 0x9c, 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0,
0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, 0x21, 0xd5, 0x14, 0xb2,
0x54, 0x66, 0x93, 0x1c, 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05,
0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, 0x3d, 0x58, 0xe0, 0x91};

static const unsigned char kAesModesCipherTextGcm192[60] = {
0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, 0xeb, 0x06, 0xfa, 0xc4,
0x87, 0x2a, 0x27, 0x57, 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84,
0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, 0x7d, 0x77, 0x3d, 0x00,
0xc1, 0x44, 0xc5, 0x25, 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47,
0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, 0xcc, 0xda, 0x27, 0x10};

static const unsigned char kAesModesCipherTextGcm256[60] = {
0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, 0xf4, 0x7f, 0x37, 0xa3,
0x2a, 0x84, 0x42, 0x7d, 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9,
0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, 0x8c, 0xb0, 0x8e, 0x48,
0x59, 0x0d, 0xbb, 0x3d, 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38,
0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, 0xbc, 0xc9, 0xf6, 0x62};

static const unsigned char kAesModesTagGcm128[16] = {
0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb,
0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47};

static const unsigned char kAesModesTagGcm192[16] = {
0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f,
0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c};

static const unsigned char kAesModesTagGcm256[16] = {
0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68,
0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b};

#endif // OPENTITAN_HW_IP_AES_MODEL_AES_MODES_H_
44 changes: 42 additions & 2 deletions hw/ip/aes/model/crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ static const EVP_CIPHER *crypto_get_EVP_cipher(int key_len,
} else { // key_len = 16
cipher = EVP_aes_128_ctr();
}
} else if (mode == kCryptoAesGcm) {
if (key_len == 32) {
cipher = EVP_aes_256_gcm();
} else if (key_len == 24) {
cipher = EVP_aes_192_gcm();
} else { // key_len = 16
cipher = EVP_aes_128_gcm();
}
} else { // kCryptoAesEcb
if (key_len == 32) {
cipher = EVP_aes_256_ecb();
Expand All @@ -66,7 +74,9 @@ static const EVP_CIPHER *crypto_get_EVP_cipher(int key_len,

int crypto_encrypt(unsigned char *output, const unsigned char *iv,
const unsigned char *input, int input_len,
const unsigned char *key, int key_len, crypto_mode_t mode) {
const unsigned char *key, int key_len, crypto_mode_t mode,
const unsigned char *aad, int aad_len, unsigned char *tag,
int tag_len) {
EVP_CIPHER_CTX *ctx;
int ret;
int len, output_len;
Expand All @@ -93,6 +103,15 @@ int crypto_encrypt(unsigned char *output, const unsigned char *iv,
// multiples of 16 bytes (the block size).
EVP_CIPHER_CTX_set_padding(ctx, 0);

// Feed AAD into cipher, when in GCM mode.
if (mode == kCryptoAesGcm) {
ret = EVP_EncryptUpdate(ctx, NULL, &output_len, aad, aad_len);
if (ret != 1) {
printf("ERROR: Encryption operation failed\n");
return -1;
}
}

// Provide encryption input, get first output bytes
ret = EVP_EncryptUpdate(ctx, output, &output_len, input, input_len);
if (ret != 1) {
Expand All @@ -108,6 +127,11 @@ int crypto_encrypt(unsigned char *output, const unsigned char *iv,
}
output_len += len;

// Fetch tag, when in GCM mode.
if (mode == kCryptoAesGcm) {
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, tag_len, tag);
}

// Free
EVP_CIPHER_CTX_free(ctx);

Expand All @@ -116,7 +140,9 @@ int crypto_encrypt(unsigned char *output, const unsigned char *iv,

int crypto_decrypt(unsigned char *output, const unsigned char *iv,
const unsigned char *input, int input_len,
const unsigned char *key, int key_len, crypto_mode_t mode) {
const unsigned char *key, int key_len, crypto_mode_t mode,
const unsigned char *aad, int aad_len, unsigned char *tag,
int tag_len) {
EVP_CIPHER_CTX *ctx;
int ret;
int len, output_len;
Expand All @@ -142,13 +168,27 @@ int crypto_decrypt(unsigned char *output, const unsigned char *iv,
// multiples of 16 bytes (the block size).
EVP_CIPHER_CTX_set_padding(ctx, 0);

// Feed AAD into cipher, when in GCM mode.
if (mode == kCryptoAesGcm) {
ret = EVP_DecryptUpdate(ctx, NULL, &output_len, aad, aad_len);
if (ret != 1) {
printf("ERROR: Encryption operation failed\n");
return -1;
}
}

// Provide decryption input, get first output bytes
ret = EVP_DecryptUpdate(ctx, output, &output_len, input, input_len);
if (ret != 1) {
printf("ERROR: Decryption operation failed\n");
return -1;
}

// Set tag, when in GCM mode.
if (mode == kCryptoAesGcm) {
EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag_len, (void *)tag);
}

// Finalize decryption, further bytes might be written
ret = EVP_DecryptFinal_ex(ctx, output + output_len, &len);
if (ret != 1) {
Expand Down
Loading

0 comments on commit fe3c200

Please sign in to comment.