From acf1a9833b46b4a5908afb1ed4b5961676d77850 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 23 Mar 2021 11:18:50 -0700 Subject: [PATCH 1/5] Fix for AES GCM with STM32H7 to use crypto hardware in all cases except IV size != 12. --- wolfcrypt/src/aes.c | 26 ++++++++++++++++++++------ wolfcrypt/src/port/st/stm32.c | 3 +++ wolfcrypt/test/test.c | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 5ced9b2f7..b68e97783 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -6987,10 +6987,14 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz /* for cases where hardware cannot be used for authTag calculate it */ /* if IV is not 12 calculate GHASH using software */ if (ivSz != GCM_NONCE_MID_SZ -#ifndef STM32_AESGCM_PARTIAL + #ifndef CRYP_HEADERWIDTHUNIT_BYTE + /* or harware that does not support partial block */ + || sz == 0 || partial != 0 + #endif + #ifndef STM32_AESGCM_PARTIAL /* or authIn is not a multiple of 4 */ - || authPadSz != authInSz || sz == 0 || partial != 0 -#endif + || authPadSz != authInSz + #endif ) { useSwGhash = 1; } @@ -7008,7 +7012,12 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz #if defined(STM32_HAL_V2) hcryp.Init.Algorithm = CRYP_AES_GCM; + #ifdef CRYP_HEADERWIDTHUNIT_BYTE + /* V2 with CRYP_DATAWIDTHUNIT_BYTE uses byte size for header */ + hcryp.Init.HeaderSize = authPadSz; + #else hcryp.Init.HeaderSize = authPadSz/sizeof(word32); + #endif #ifdef STM32_AESGCM_PARTIAL hcryp.Init.HeaderPadSize = authPadSz - authInSz; #endif @@ -7448,10 +7457,10 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, /* for cases where hardware cannot be used for authTag calculate it */ /* if IV is not 12 calculate GHASH using software */ if (ivSz != GCM_NONCE_MID_SZ || sz == 0 || partial != 0 -#ifndef STM32_AESGCM_PARTIAL + #ifndef STM32_AESGCM_PARTIAL /* or authIn is not a multiple of 4 */ || authPadSz != authInSz -#endif + #endif ) { GHASH(aes, authIn, authInSz, in, sz, (byte*)tag, sizeof(tag)); wc_AesEncrypt(aes, (byte*)ctr, (byte*)partialBlock); @@ -7492,7 +7501,12 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, #if defined(STM32_HAL_V2) hcryp.Init.Algorithm = CRYP_AES_GCM; + #ifdef CRYP_HEADERWIDTHUNIT_BYTE + /* V2 with CRYP_DATAWIDTHUNIT_BYTE uses byte size for header */ + hcryp.Init.HeaderSize = authPadSz; + #else hcryp.Init.HeaderSize = authPadSz/sizeof(word32); + #endif #ifdef STM32_AESGCM_PARTIAL hcryp.Init.HeaderPadSize = authPadSz - authInSz; #endif @@ -7503,7 +7517,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, /* GCM payload phase - can handle partial blocks */ status = HAL_CRYP_Decrypt(&hcryp, (uint32_t*)in, (blocks * AES_BLOCK_SIZE) + partial, (uint32_t*)out, STM32_HAL_TIMEOUT); - if (status == HAL_OK && tagComputed == 0) { + if (status == HAL_OK && !tagComputed) { /* Compute the authTag */ status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag, STM32_HAL_TIMEOUT); diff --git a/wolfcrypt/src/port/st/stm32.c b/wolfcrypt/src/port/st/stm32.c index 2c23ed48c..3a1fb13bc 100644 --- a/wolfcrypt/src/port/st/stm32.c +++ b/wolfcrypt/src/port/st/stm32.c @@ -294,6 +294,9 @@ int wc_Stm32_Aes_Init(Aes* aes, CRYP_HandleTypeDef* hcryp) hcryp->Init.pKey = (STM_CRYPT_TYPE*)aes->key; #ifdef STM32_HAL_V2 hcryp->Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE; + #ifdef CRYP_HEADERWIDTHUNIT_BYTE + hcryp->Init.HeaderWidthUnit = CRYP_HEADERWIDTHUNIT_BYTE; + #endif #endif return 0; diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 5be88a07a..7f315b10e 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -9895,7 +9895,7 @@ WOLFSSL_TEST_SUBROUTINE int aesgcm_test(void) /* Variable plain text length test */ for (plen=1; plen<(int)sizeof(p); plen++) { /* AES-GCM encrypt and decrypt both use AES encrypt internally */ - result = wc_AesGcmEncrypt(enc, resultC, p, (word32)plen, iv1, + result = wc_AesGcmEncrypt(enc, resultC, resultP, (word32)plen, iv1, sizeof(iv1), resultT, sizeof(resultT), a, sizeof(a)); #if defined(WOLFSSL_ASYNC_CRYPT) result = wc_AsyncWait(result, &enc->asyncDev, WC_ASYNC_FLAG_NONE); From 89e4bae8d26ea934b5bbaeacfdaa723ec4016eda Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 12 Apr 2021 16:57:57 -0700 Subject: [PATCH 2/5] Fix for STM32 AES GCM decrypt to support partial (not multiple of 4) for auth tag calculation. --- wolfcrypt/src/aes.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index b68e97783..5b2b70856 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -7456,7 +7456,11 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, /* for cases where hardware cannot be used for authTag calculate it */ /* if IV is not 12 calculate GHASH using software */ - if (ivSz != GCM_NONCE_MID_SZ || sz == 0 || partial != 0 + if (ivSz != GCM_NONCE_MID_SZ + #ifndef CRYP_HEADERWIDTHUNIT_BYTE + /* or harware that does not support partial block */ + || sz == 0 || partial != 0 + #endif #ifndef STM32_AESGCM_PARTIAL /* or authIn is not a multiple of 4 */ || authPadSz != authInSz @@ -7515,6 +7519,18 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, HAL_CRYP_Init(&hcryp); /* GCM payload phase - can handle partial blocks */ + #ifdef CRYP_HEADERWIDTHUNIT_BYTE + { + /* clear remainder of partial input (for 32-bit uint) */ + word32 remain = (partial & 3); + if (remain > 0) + remain = 4 - remain; + while (sz > 0 && remain > 0) { + ((byte*)in)[sz + remain - 1] = 0; + remain--; + } + } + #endif status = HAL_CRYP_Decrypt(&hcryp, (uint32_t*)in, (blocks * AES_BLOCK_SIZE) + partial, (uint32_t*)out, STM32_HAL_TIMEOUT); if (status == HAL_OK && !tagComputed) { From 54e111aa85c4a02bc6cf21371a955047f2a05767 Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 12 Apr 2021 17:02:35 -0700 Subject: [PATCH 3/5] Update copy/paste error in comment. --- wolfcrypt/src/aes.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 5b2b70856..a5ce9b0f0 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -7013,7 +7013,7 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz #if defined(STM32_HAL_V2) hcryp.Init.Algorithm = CRYP_AES_GCM; #ifdef CRYP_HEADERWIDTHUNIT_BYTE - /* V2 with CRYP_DATAWIDTHUNIT_BYTE uses byte size for header */ + /* V2 with CRYP_HEADERWIDTHUNIT_BYTE uses byte size for header */ hcryp.Init.HeaderSize = authPadSz; #else hcryp.Init.HeaderSize = authPadSz/sizeof(word32); @@ -7506,7 +7506,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, #if defined(STM32_HAL_V2) hcryp.Init.Algorithm = CRYP_AES_GCM; #ifdef CRYP_HEADERWIDTHUNIT_BYTE - /* V2 with CRYP_DATAWIDTHUNIT_BYTE uses byte size for header */ + /* V2 with CRYP_HEADERWIDTHUNIT_BYTE uses byte size for header */ hcryp.Init.HeaderSize = authPadSz; #else hcryp.Init.HeaderSize = authPadSz/sizeof(word32); From 7cfd22304e40a815e7bf1bc3d2ace3d03dd95968 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Apr 2021 11:58:45 -0700 Subject: [PATCH 4/5] Fix to improve STM32 AES GCM with partial blocks. Use a local buffer for partial remainder and make sure remainder is zero'd. --- wolfcrypt/src/aes.c | 71 +++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index a5ce9b0f0..4b940cfc5 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -7021,13 +7021,33 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz #ifdef STM32_AESGCM_PARTIAL hcryp.Init.HeaderPadSize = authPadSz - authInSz; #endif - ByteReverseWords(partialBlock, ctr, AES_BLOCK_SIZE); - hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock; + #ifdef CRYP_KEYIVCONFIG_ONCE + /* allows repeated calls to HAL_CRYP_Encrypt */ + hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE; + #endif + ByteReverseWords(ctr, ctr, AES_BLOCK_SIZE); + hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr; HAL_CRYP_Init(&hcryp); + #ifndef CRYP_KEYIVCONFIG_ONCE /* GCM payload phase - can handle partial blocks */ status = HAL_CRYP_Encrypt(&hcryp, (uint32_t*)in, (blocks * AES_BLOCK_SIZE) + partial, (uint32_t*)out, STM32_HAL_TIMEOUT); + #else + /* GCM payload phase - blocks */ + if (blocks) { + status = HAL_CRYP_Encrypt(&hcryp, (uint32_t*)in, + (blocks * AES_BLOCK_SIZE), (uint32_t*)out, STM32_HAL_TIMEOUT); + } + /* GCM payload phase - partial remainder */ + if (status == HAL_OK && (partial != 0 || blocks == 0)) { + XMEMSET(partialBlock, 0, sizeof(partialBlock)); + XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial); + status = HAL_CRYP_Encrypt(&hcryp, (uint32_t*)partialBlock, partial, + (uint32_t*)partialBlock, STM32_HAL_TIMEOUT); + XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial); + } + #endif if (status == HAL_OK && !useSwGhash) { /* Compute the authTag */ status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag, @@ -7466,10 +7486,10 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, || authPadSz != authInSz #endif ) { - GHASH(aes, authIn, authInSz, in, sz, (byte*)tag, sizeof(tag)); - wc_AesEncrypt(aes, (byte*)ctr, (byte*)partialBlock); - xorbuf(tag, partialBlock, sizeof(tag)); - tagComputed = 1; + GHASH(aes, authIn, authInSz, in, sz, (byte*)tag, sizeof(tag)); + wc_AesEncrypt(aes, (byte*)ctr, (byte*)partialBlock); + xorbuf(tag, partialBlock, sizeof(tag)); + tagComputed = 1; } /* if using hardware for authentication tag make sure its aligned and zero padded */ @@ -7514,25 +7534,32 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, #ifdef STM32_AESGCM_PARTIAL hcryp.Init.HeaderPadSize = authPadSz - authInSz; #endif - ByteReverseWords(partialBlock, ctr, AES_BLOCK_SIZE); - hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock; + #ifdef CRYP_KEYIVCONFIG_ONCE + /* allows repeated calls to HAL_CRYP_Decrypt */ + hcryp.Init.KeyIVConfigSkip = CRYP_KEYIVCONFIG_ONCE; + #endif + ByteReverseWords(ctr, ctr, AES_BLOCK_SIZE); + hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr; HAL_CRYP_Init(&hcryp); - /* GCM payload phase - can handle partial blocks */ - #ifdef CRYP_HEADERWIDTHUNIT_BYTE - { - /* clear remainder of partial input (for 32-bit uint) */ - word32 remain = (partial & 3); - if (remain > 0) - remain = 4 - remain; - while (sz > 0 && remain > 0) { - ((byte*)in)[sz + remain - 1] = 0; - remain--; - } - } - #endif + #ifndef CRYP_KEYIVCONFIG_ONCE status = HAL_CRYP_Decrypt(&hcryp, (uint32_t*)in, (blocks * AES_BLOCK_SIZE) + partial, (uint32_t*)out, STM32_HAL_TIMEOUT); + #else + /* GCM payload phase - blocks */ + if (blocks) { + status = HAL_CRYP_Decrypt(&hcryp, (uint32_t*)in, + (blocks * AES_BLOCK_SIZE), (uint32_t*)out, STM32_HAL_TIMEOUT); + } + /* GCM payload phase - partial remainder */ + if (status == HAL_OK && (partial != 0 || blocks == 0)) { + XMEMSET(partialBlock, 0, sizeof(partialBlock)); + XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial); + status = HAL_CRYP_Decrypt(&hcryp, (uint32_t*)partialBlock, partial, +( uint32_t*)partialBlock, STM32_HAL_TIMEOUT); + XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial); + } + #endif if (status == HAL_OK && !tagComputed) { /* Compute the authTag */ status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag, @@ -7618,7 +7645,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, if (status != SUCCESS) ret = AES_GCM_AUTH_E; if (tagComputed == 0) - XMEMCPY(tag, partialBlock, authTagSz); + XMEMCPY(tag, partialBlock, authTagSz); #endif /* WOLFSSL_STM32_CUBEMX */ wolfSSL_CryptHwMutexUnLock(); From 099f88e45bc1ebdb9fd1e6387dbdeb274dafadc9 Mon Sep 17 00:00:00 2001 From: David Garske Date: Fri, 16 Apr 2021 12:02:04 -0700 Subject: [PATCH 5/5] Revert the change to test.c. --- wolfcrypt/test/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 7f315b10e..5be88a07a 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -9895,7 +9895,7 @@ WOLFSSL_TEST_SUBROUTINE int aesgcm_test(void) /* Variable plain text length test */ for (plen=1; plen<(int)sizeof(p); plen++) { /* AES-GCM encrypt and decrypt both use AES encrypt internally */ - result = wc_AesGcmEncrypt(enc, resultC, resultP, (word32)plen, iv1, + result = wc_AesGcmEncrypt(enc, resultC, p, (word32)plen, iv1, sizeof(iv1), resultT, sizeof(resultT), a, sizeof(a)); #if defined(WOLFSSL_ASYNC_CRYPT) result = wc_AsyncWait(result, &enc->asyncDev, WC_ASYNC_FLAG_NONE);