Merge branch 'bugfix/s2_gcm_hw' into 'master'

aes: Fixed tag sometime being wrong for HW GCM

See merge request espressif/esp-idf!8009
This commit is contained in:
Ivan Grokhotkov
2020-03-19 18:06:25 +08:00
5 changed files with 187 additions and 66 deletions

View File

@@ -208,7 +208,7 @@ menu "mbedTLS"
config MBEDTLS_HARDWARE_GCM config MBEDTLS_HARDWARE_GCM
bool "Enable partially hardware accelerated GCM" bool "Enable partially hardware accelerated GCM"
depends on IDF_TARGET_ESP32S2 && MBEDTLS_HARDWARE_AES depends on IDF_TARGET_ESP32S2 && MBEDTLS_HARDWARE_AES
default n default y
help help
Enable partially hardware accelerated GCM. GHASH calculation is still done Enable partially hardware accelerated GCM. GHASH calculation is still done
in software. in software.

View File

@@ -345,7 +345,6 @@ static int esp_aes_process_dma_ext_ram(esp_aes_context *ctx, const unsigned char
unsigned char *input_buf = NULL; unsigned char *input_buf = NULL;
unsigned char *output_buf = NULL; unsigned char *output_buf = NULL;
const unsigned char *dma_input; const unsigned char *dma_input;
chunk_len = MIN(AES_MAX_CHUNK_WRITE_SIZE, len); chunk_len = MIN(AES_MAX_CHUNK_WRITE_SIZE, len);
if (realloc_input) { if (realloc_input) {
@@ -1290,6 +1289,8 @@ void esp_aes_gcm_init( esp_gcm_context *ctx)
} }
bzero(ctx, sizeof(esp_gcm_context)); bzero(ctx, sizeof(esp_gcm_context));
ctx->gcm_state = ESP_AES_GCM_STATE_INIT;
} }
/* Function to clear AES-GCM context */ /* Function to clear AES-GCM context */
@@ -1298,7 +1299,6 @@ void esp_aes_gcm_free( esp_gcm_context *ctx)
if (ctx == NULL) { if (ctx == NULL) {
return; return;
} }
bzero(ctx, sizeof(esp_gcm_context)); bzero(ctx, sizeof(esp_gcm_context));
} }
@@ -1333,15 +1333,18 @@ int esp_aes_gcm_starts( esp_gcm_context *ctx,
return -1; return -1;
} }
/* Initialize AES-GCM context */ /* Initialize AES-GCM context */
memset(ctx->ghash, 0, sizeof(ctx->ghash));
ctx->data_len = 0;
ctx->iv = iv; ctx->iv = iv;
ctx->iv_len = iv_len; ctx->iv_len = iv_len;
ctx->aad = aad; ctx->aad = aad;
ctx->aad_len = aad_len; ctx->aad_len = aad_len;
ctx->gcm_state = ESP_AES_GCM_STATE_INIT;
ctx->mode = mode; ctx->mode = mode;
/* H and the lookup table are only generated once per ctx */
if (ctx->gcm_state == ESP_AES_GCM_STATE_INIT) {
/* Lock the AES engine to calculate ghash key H in hardware */ /* Lock the AES engine to calculate ghash key H in hardware */
esp_aes_acquire_hardware(); esp_aes_acquire_hardware();
esp_aes_setkey_hardware( &ctx->aes_ctx, mode); esp_aes_setkey_hardware( &ctx->aes_ctx, mode);
@@ -1354,7 +1357,11 @@ int esp_aes_gcm_starts( esp_gcm_context *ctx,
memcpy(ctx->H, (uint8_t *)AES_H_BASE, AES_BLOCK_BYTES); memcpy(ctx->H, (uint8_t *)AES_H_BASE, AES_BLOCK_BYTES);
esp_aes_release_hardware(); esp_aes_release_hardware();
gcm_gen_table(ctx); gcm_gen_table(ctx);
}
ctx->gcm_state = ESP_AES_GCM_STATE_START;
/* Once H is obtained we need to derive J0 (Initial Counter Block) */ /* Once H is obtained we need to derive J0 (Initial Counter Block) */
esp_gcm_derive_J0(ctx); esp_gcm_derive_J0(ctx);
@@ -1367,7 +1374,6 @@ int esp_aes_gcm_starts( esp_gcm_context *ctx,
esp_gcm_ghash(ctx, ctx->aad, ctx->aad_len, ctx->ghash); esp_gcm_ghash(ctx, ctx->aad, ctx->aad_len, ctx->ghash);
return ( 0 ); return ( 0 );
} }
@@ -1400,7 +1406,7 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
/* If this is the first time esp_gcm_update is getting called /* If this is the first time esp_gcm_update is getting called
* calculate GHASH on aad and preincrement the ICB * calculate GHASH on aad and preincrement the ICB
*/ */
if (ctx->gcm_state == ESP_AES_GCM_STATE_INIT) { if (ctx->gcm_state == ESP_AES_GCM_STATE_START) {
/* Jo needs to be incremented first time, later the CTR /* Jo needs to be incremented first time, later the CTR
* operation will auto update it * operation will auto update it
*/ */
@@ -1410,20 +1416,23 @@ int esp_aes_gcm_update( esp_gcm_context *ctx,
memcpy(nonce_counter, ctx->J0, AES_BLOCK_BYTES); memcpy(nonce_counter, ctx->J0, AES_BLOCK_BYTES);
} }
/* Perform intermediate GHASH on "encrypted" data during decryption */
if (ctx->mode == ESP_AES_DECRYPT) {
esp_gcm_ghash(ctx, input, length, ctx->ghash);
}
/* Output = GCTR(J0, Input): Encrypt/Decrypt the input */ /* Output = GCTR(J0, Input): Encrypt/Decrypt the input */
esp_aes_crypt_ctr(&ctx->aes_ctx, length, &nc_off, nonce_counter, stream, input, output); esp_aes_crypt_ctr(&ctx->aes_ctx, length, &nc_off, nonce_counter, stream, input, output);
/* ICB gets auto incremented after GCTR operation here so update the context */ /* ICB gets auto incremented after GCTR operation here so update the context */
memcpy(ctx->J0, nonce_counter, AES_BLOCK_BYTES); memcpy(ctx->J0, nonce_counter, AES_BLOCK_BYTES);
/* Keep updating the length counter for final tag calculation */ /* Keep updating the length counter for final tag calculation */
ctx->data_len += length; ctx->data_len += length;
/* Perform intermediate GHASH on "encrypted" data irrespective of mode */ /* Perform intermediate GHASH on "encrypted" data during encryption*/
if (ctx->mode == ESP_AES_DECRYPT) { if (ctx->mode == ESP_AES_ENCRYPT) {
esp_gcm_ghash(ctx, input, length, ctx->ghash);
} else {
esp_gcm_ghash(ctx, output, length, ctx->ghash); esp_gcm_ghash(ctx, output, length, ctx->ghash);
} }
return 0; return 0;

View File

@@ -36,6 +36,7 @@ extern "C" {
typedef enum { typedef enum {
ESP_AES_GCM_STATE_INIT, ESP_AES_GCM_STATE_INIT,
ESP_AES_GCM_STATE_START,
ESP_AES_GCM_STATE_UPDATE, ESP_AES_GCM_STATE_UPDATE,
ESP_AES_GCM_STATE_FINISH ESP_AES_GCM_STATE_FINISH
} esp_aes_gcm_state; } esp_aes_gcm_state;

View File

@@ -547,6 +547,50 @@ void aes_psram_ctr_test(uint32_t input_buf_caps, uint32_t output_buf_caps)
free(decryptedtext); free(decryptedtext);
} }
void aes_psram_one_buf_ctr_test(void)
{
mbedtls_aes_context ctx;
uint8_t nonce[16];
uint8_t key[16];
uint8_t stream_block[16];
size_t SZ = 6000;
size_t ALIGNMENT_SIZE_BYTES = 16;
memset(nonce, 0x2F, 16);
memset(key, 0x1E, 16);
// allocate internal memory
uint8_t *buf = heap_caps_malloc(SZ + ALIGNMENT_SIZE_BYTES, MALLOC_CAP_SPIRAM);
TEST_ASSERT_NOT_NULL(buf);
mbedtls_aes_init(&ctx);
mbedtls_aes_setkey_enc(&ctx, key, 128);
memset(buf, 0x26, SZ + ALIGNMENT_SIZE_BYTES);
size_t offset;
/* Shift buffers and test for all different misalignments */
for (int i = 0; i < ALIGNMENT_SIZE_BYTES; i++ ) {
// Encrypt with input buffer in external ram
offset = 0;
memset(buf, 0x26, SZ + ALIGNMENT_SIZE_BYTES);
memset(nonce, 0x2F, 16);
mbedtls_aes_crypt_ctr(&ctx, SZ, &offset, nonce, stream_block, buf + i, buf + i);
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_cipher_psram_end, buf + i + SZ - 32, 32);
// Decrypt
offset = 0;
memset(nonce, 0x2F, 16);
// Decrypt with input buffer in instruction memory, the crypto DMA can't access this
mbedtls_aes_crypt_ctr(&ctx, SZ, &offset, nonce, stream_block, buf + i, buf);
TEST_ASSERT_EACH_EQUAL_HEX8(0x26, buf + i, SZ - i);
}
free(buf);
}
const uint8_t long_input[] = { const uint8_t long_input[] = {
0xf7, 0xe6, 0x6b, 0x8d, 0x2e, 0xbf, 0x88, 0xd6, 0xf7, 0xe6, 0x6b, 0x8d, 0x2e, 0xbf, 0x88, 0xd6,
0xb0, 0x77, 0xdf, 0x72, 0xbf, 0xa8, 0x0, 0x55, 0xb0, 0x77, 0xdf, 0x72, 0xbf, 0xa8, 0x0, 0x55,
@@ -1116,6 +1160,7 @@ TEST_CASE("mbedtls AES PSRAM tests", "[aes]")
aes_psram_ctr_test(MALLOC_CAP_INTERNAL, MALLOC_CAP_SPIRAM); aes_psram_ctr_test(MALLOC_CAP_INTERNAL, MALLOC_CAP_SPIRAM);
aes_psram_ctr_test(MALLOC_CAP_SPIRAM, MALLOC_CAP_INTERNAL); aes_psram_ctr_test(MALLOC_CAP_SPIRAM, MALLOC_CAP_INTERNAL);
aes_psram_ctr_test(MALLOC_CAP_SPIRAM, MALLOC_CAP_SPIRAM); aes_psram_ctr_test(MALLOC_CAP_SPIRAM, MALLOC_CAP_SPIRAM);
aes_psram_one_buf_ctr_test();
} }
/* Tests how crypto DMA handles data from iCache */ /* Tests how crypto DMA handles data from iCache */
@@ -1131,3 +1176,69 @@ TEST_CASE("mbedtls AES GCM self-tests", "[aes]")
TEST_ASSERT_FALSE_MESSAGE(mbedtls_gcm_self_test(1), "AES GCM self-test should pass."); TEST_ASSERT_FALSE_MESSAGE(mbedtls_gcm_self_test(1), "AES GCM self-test should pass.");
} }
TEST_CASE("mbedtls AES GCM crypt-and-tag", "[aes]")
{
const unsigned CALL_SZ = 32 * 1024;
mbedtls_gcm_context ctx;
unsigned char tag_buf[16];
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
uint8_t iv[16];
uint8_t key[16];
memset(iv, 0xEE, 16);
memset(key, 0x44, 16);
// allocate internal memory
uint8_t *buf = heap_caps_malloc(CALL_SZ, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
TEST_ASSERT_NOT_NULL(buf);
uint8_t aad[16];
memset(aad, 0x22, 16);
mbedtls_gcm_init(&ctx);
mbedtls_gcm_setkey( &ctx, cipher, key, 128);
memset(buf, 0xAA, CALL_SZ);
mbedtls_gcm_crypt_and_tag(&ctx, MBEDTLS_AES_ENCRYPT, CALL_SZ, iv, sizeof(iv), aad, sizeof(aad), buf, buf, 16, tag_buf);
/* Sanity check: make sure the last ciphertext block matches
what we expect to see.
Last block and tag produced via this Python:
import os, binascii
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = b'\x44' * 16
iv = b'\xEE' * 16
data = b'\xAA' * 100
aad = b'\x22 * 16
aesgcm = AESGCM(key)
ct = aesgcm.encrypt(iv, data, aad)
*/
const uint8_t expected_last_block[] = {
0x7d, 0x3d, 0x16, 0x84, 0xd0, 0xb4, 0x38, 0x30,
0xd1, 0x24, 0x6f, 0x7e, 0x9a, 0x9c, 0x81, 0x58,
};
const uint8_t expected_tag[] = {
0x7e, 0x16, 0x04, 0x07, 0x4b, 0x7e, 0x6b, 0xf7,
0x5d, 0xce, 0x9e, 0x7d, 0x3f, 0x85, 0xc5, 0xa5,
};
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_last_block, buf + CALL_SZ - 16, 16);
TEST_ASSERT_EQUAL_HEX8_ARRAY(expected_tag, tag_buf, 16);
memset(iv, 0xEE, 16);
TEST_ASSERT_EQUAL(mbedtls_gcm_auth_decrypt(&ctx, CALL_SZ, iv, sizeof(iv), aad, sizeof(aad), expected_tag, sizeof(expected_tag), buf, buf), 0);
TEST_ASSERT_EACH_EQUAL_HEX8(0xAA, buf, CALL_SZ);
free(buf);
}

View File

@@ -495,7 +495,7 @@ UT_034:
UT_035: UT_035:
extends: .unit_test_s2_template extends: .unit_test_s2_template
parallel: 29 parallel: 30
tags: tags:
- ESP32S2_IDF - ESP32S2_IDF
- UT_T1_1 - UT_T1_1