Fixes for STM32 CubeMX HAL with AES GCM. Fix AES GCM authentication header size, which expects size as number of 32-bit values. Fix the authentication size round up logic. Fix to use software for authentication tag if authentication data size is not multiple of 4. Fix to ensure 32-bit aligned buffers are used.

This commit is contained in:
David Garske
2020-05-11 15:46:31 -07:00
parent 7c98451f24
commit 778b5dd9d5

View File

@ -1474,7 +1474,7 @@ static const word32 Td[4][256] = {
#ifdef HAVE_AES_DECRYPT #ifdef HAVE_AES_DECRYPT
#if (defined(HAVE_AES_CBC) && !defined(WOLFSSL_DEVCRYPTO_CBC)) \ #if (defined(HAVE_AES_CBC) && !defined(WOLFSSL_DEVCRYPTO_CBC)) \
|| defined(WOLFSSL_AES_DIRECT) || defined(WOLFSSL_AES_DIRECT)
static const byte Td4[256] = static const byte Td4[256] =
{ {
0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
@ -5930,9 +5930,9 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz
int status = HAL_OK; int status = HAL_OK;
word32 blocks = sz / AES_BLOCK_SIZE; word32 blocks = sz / AES_BLOCK_SIZE;
word32 partial = sz % AES_BLOCK_SIZE; word32 partial = sz % AES_BLOCK_SIZE;
byte tag[AES_BLOCK_SIZE]; word32 tag[AES_BLOCK_SIZE/sizeof(word32)];
byte partialBlock[AES_BLOCK_SIZE]; word32 partialBlock[AES_BLOCK_SIZE/sizeof(word32)];
byte ctr[AES_BLOCK_SIZE]; word32 ctr[AES_BLOCK_SIZE/sizeof(word32)];
byte* authInPadded = NULL; byte* authInPadded = NULL;
int authPadSz; int authPadSz;
@ -5953,18 +5953,20 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz
XMEMSET(ctr, 0, AES_BLOCK_SIZE); XMEMSET(ctr, 0, AES_BLOCK_SIZE);
if (ivSz == GCM_NONCE_MID_SZ) { if (ivSz == GCM_NONCE_MID_SZ) {
byte* pCtr = (byte*)ctr;
XMEMCPY(ctr, iv, ivSz); XMEMCPY(ctr, iv, ivSz);
ctr[AES_BLOCK_SIZE - 1] = 1; pCtr[AES_BLOCK_SIZE - 1] = 1;
} }
else { else {
GHASH(aes, NULL, 0, iv, ivSz, ctr, AES_BLOCK_SIZE); GHASH(aes, NULL, 0, iv, ivSz, (byte*)ctr, AES_BLOCK_SIZE);
} }
/* Hardware requires counter + 1 */ /* Hardware requires counter + 1 */
IncrementGcmCounter(ctr); IncrementGcmCounter((byte*)ctr);
if (authInSz == 0 || (authInSz % AES_BLOCK_SIZE) != 0) { /* Authentication buffer - must be 4-byte multiple zero padded */
/* Need to pad the AAD to a full block with zeros. */ authPadSz = authInSz % sizeof(word32);
authPadSz = ((authInSz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; if (authInSz == 0 || authPadSz != 0) {
authPadSz = authInSz + sizeof(word32) - authPadSz;
authInPadded = (byte*)XMALLOC(authPadSz, aes->heap, authInPadded = (byte*)XMALLOC(authPadSz, aes->heap,
DYNAMIC_TYPE_TMP_BUFFER); DYNAMIC_TYPE_TMP_BUFFER);
if (authInPadded == NULL) { if (authInPadded == NULL) {
@ -5981,7 +5983,7 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz
#ifdef WOLFSSL_STM32_CUBEMX #ifdef WOLFSSL_STM32_CUBEMX
hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr; hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr;
hcryp.Init.Header = (STM_CRYPT_TYPE*)authInPadded; hcryp.Init.Header = (STM_CRYPT_TYPE*)authInPadded;
hcryp.Init.HeaderSize = authInSz; hcryp.Init.HeaderSize = authPadSz/sizeof(word32);
#ifdef STM32_CRYPTO_AES_ONLY #ifdef STM32_CRYPTO_AES_ONLY
/* Set the CRYP parameters */ /* Set the CRYP parameters */
@ -5994,12 +5996,12 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz
status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT); status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
if (status == HAL_OK) { if (status == HAL_OK) {
/* GCM header phase */ /* GCM header phase */
hcryp.Init.GCMCMACPhase = CRYP_HEADER_PHASE; hcryp.Init.GCMCMACPhase = CRYP_HEADER_PHASE;
status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT); status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
} }
if (status == HAL_OK) { if (status == HAL_OK) {
/* GCM payload phase - blocks */ /* GCM payload phase - blocks */
hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE; hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE;
if (blocks) { if (blocks) {
status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)in, status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)in,
(blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT); (blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT);
@ -6020,7 +6022,7 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz
} }
#elif defined(STM32_HAL_V2) #elif defined(STM32_HAL_V2)
hcryp.Init.Algorithm = CRYP_AES_GCM; hcryp.Init.Algorithm = CRYP_AES_GCM;
ByteReverseWords((word32*)partialBlock, (word32*)ctr, AES_BLOCK_SIZE); ByteReverseWords(partialBlock, ctr, AES_BLOCK_SIZE);
hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock; hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock;
HAL_CRYP_Init(&hcryp); HAL_CRYP_Init(&hcryp);
@ -6071,12 +6073,12 @@ static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz
if (ret == 0) { if (ret == 0) {
/* return authTag */ /* return authTag */
if (authTag) { if (authTag) {
/* STM32 GCM won't compute Auth correctly for partial or /* For STM32 GCM fallback to software if partial AES block or
when IV != 12, so use software here */ * IV != 12 or when auth data is not 4 byte aligned */
if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ) { if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ || authInPadded != authIn) {
DecrementGcmCounter(ctr); /* hardware requires +1, so subtract it */ DecrementGcmCounter((byte*)ctr); /* hardware requires +1, so subtract it */
GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz); GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
wc_AesEncrypt(aes, ctr, tag); wc_AesEncrypt(aes, (byte*)ctr, (byte*)tag);
xorbuf(authTag, tag, authTagSz); xorbuf(authTag, tag, authTagSz);
} }
else { else {
@ -6366,9 +6368,9 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
int status = HAL_OK; int status = HAL_OK;
word32 blocks = sz / AES_BLOCK_SIZE; word32 blocks = sz / AES_BLOCK_SIZE;
word32 partial = sz % AES_BLOCK_SIZE; word32 partial = sz % AES_BLOCK_SIZE;
byte tag[AES_BLOCK_SIZE]; word32 tag[AES_BLOCK_SIZE/sizeof(word32)];
byte partialBlock[AES_BLOCK_SIZE]; word32 partialBlock[AES_BLOCK_SIZE/sizeof(word32)];
byte ctr[AES_BLOCK_SIZE]; word32 ctr[AES_BLOCK_SIZE/sizeof(word32)];
byte* authInPadded = NULL; byte* authInPadded = NULL;
int authPadSz; int authPadSz;
@ -6389,18 +6391,20 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
XMEMSET(ctr, 0, AES_BLOCK_SIZE); XMEMSET(ctr, 0, AES_BLOCK_SIZE);
if (ivSz == GCM_NONCE_MID_SZ) { if (ivSz == GCM_NONCE_MID_SZ) {
byte* pCtr = (byte*)ctr;
XMEMCPY(ctr, iv, ivSz); XMEMCPY(ctr, iv, ivSz);
ctr[AES_BLOCK_SIZE - 1] = 1; pCtr[AES_BLOCK_SIZE - 1] = 1;
} }
else { else {
GHASH(aes, NULL, 0, iv, ivSz, ctr, AES_BLOCK_SIZE); GHASH(aes, NULL, 0, iv, ivSz, (byte*)ctr, AES_BLOCK_SIZE);
} }
/* Hardware requires counter + 1 */ /* Hardware requires counter + 1 */
IncrementGcmCounter(ctr); IncrementGcmCounter((byte*)ctr);
if (authInSz == 0 || (authInSz % AES_BLOCK_SIZE) != 0) { /* Authentication buffer - must be 4-byte multiple zero padded */
/* Need to pad the AAD to a full block with zeros. */ authPadSz = authInSz % sizeof(word32);
authPadSz = ((authInSz / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; if (authInSz == 0 || authPadSz != 0) {
authPadSz = authInSz + sizeof(word32) - authPadSz;
authInPadded = (byte*)XMALLOC(authPadSz, aes->heap, authInPadded = (byte*)XMALLOC(authPadSz, aes->heap,
DYNAMIC_TYPE_TMP_BUFFER); DYNAMIC_TYPE_TMP_BUFFER);
if (authInPadded == NULL) { if (authInPadded == NULL) {
@ -6417,7 +6421,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
#ifdef WOLFSSL_STM32_CUBEMX #ifdef WOLFSSL_STM32_CUBEMX
hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr; hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr;
hcryp.Init.Header = (STM_CRYPT_TYPE*)authInPadded; hcryp.Init.Header = (STM_CRYPT_TYPE*)authInPadded;
hcryp.Init.HeaderSize = authInSz; hcryp.Init.HeaderSize = authPadSz/sizeof(word32);
#ifdef STM32_CRYPTO_AES_ONLY #ifdef STM32_CRYPTO_AES_ONLY
/* Set the CRYP parameters */ /* Set the CRYP parameters */
@ -6435,7 +6439,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
} }
if (status == HAL_OK) { if (status == HAL_OK) {
/* GCM payload phase - blocks */ /* GCM payload phase - blocks */
hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE; hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE;
if (blocks) { if (blocks) {
status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)in, status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)in,
(blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT); (blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT);
@ -6445,18 +6449,18 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
/* GCM payload phase - partial remainder */ /* GCM payload phase - partial remainder */
XMEMSET(partialBlock, 0, sizeof(partialBlock)); XMEMSET(partialBlock, 0, sizeof(partialBlock));
XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial); XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial);
status = HAL_CRYPEx_AES_Auth(&hcryp, partialBlock, partial, status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)partialBlock, partial,
partialBlock, STM32_HAL_TIMEOUT); (byte*)partialBlock, STM32_HAL_TIMEOUT);
XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial); XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial);
} }
if (status == HAL_OK) { if (status == HAL_OK) {
/* GCM final phase */ /* GCM final phase */
hcryp.Init.GCMCMACPhase = CRYP_FINAL_PHASE; hcryp.Init.GCMCMACPhase = CRYP_FINAL_PHASE;
status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, tag, STM32_HAL_TIMEOUT); status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, (byte*)tag, STM32_HAL_TIMEOUT);
} }
#elif defined(STM32_HAL_V2) #elif defined(STM32_HAL_V2)
hcryp.Init.Algorithm = CRYP_AES_GCM; hcryp.Init.Algorithm = CRYP_AES_GCM;
ByteReverseWords((word32*)partialBlock, (word32*)ctr, AES_BLOCK_SIZE); ByteReverseWords(partialBlock, ctr, AES_BLOCK_SIZE);
hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock; hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock;
HAL_CRYP_Init(&hcryp); HAL_CRYP_Init(&hcryp);
@ -6479,13 +6483,13 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
/* GCM payload phase - partial remainder */ /* GCM payload phase - partial remainder */
XMEMSET(partialBlock, 0, sizeof(partialBlock)); XMEMSET(partialBlock, 0, sizeof(partialBlock));
XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial); XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial);
status = HAL_CRYPEx_AESGCM_Decrypt(&hcryp, partialBlock, partial, status = HAL_CRYPEx_AESGCM_Decrypt(&hcryp, (byte*)partialBlock, partial,
partialBlock, STM32_HAL_TIMEOUT); (byte*)partialBlock, STM32_HAL_TIMEOUT);
XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial); XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial);
} }
if (status == HAL_OK) { if (status == HAL_OK) {
/* Compute the authTag */ /* Compute the authTag */
status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, tag, STM32_HAL_TIMEOUT); status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, (byte*)tag, STM32_HAL_TIMEOUT);
} }
#endif #endif
@ -6509,15 +6513,17 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out,
ret = AES_GCM_AUTH_E; ret = AES_GCM_AUTH_E;
#endif /* WOLFSSL_STM32_CUBEMX */ #endif /* WOLFSSL_STM32_CUBEMX */
/* STM32 GCM hardware only supports IV of 12 bytes, so use software for auth */ /* For STM32 GCM fallback to software if partial AES block or
if (sz == 0 || ivSz != GCM_NONCE_MID_SZ) { * IV != 12 or when auth data is not 4 byte aligned */
DecrementGcmCounter(ctr); /* hardware requires +1, so subtract it */ if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ || authInPadded != authIn) {
GHASH(aes, authIn, authInSz, in, sz, tag, sizeof(tag)); DecrementGcmCounter((byte*)ctr); /* hardware requires +1, so subtract it */
wc_AesEncrypt(aes, ctr, partialBlock); GHASH(aes, authIn, authInSz, in, sz, (byte*)tag, sizeof(tag));
wc_AesEncrypt(aes, (byte*)ctr, (byte*)partialBlock);
xorbuf(tag, partialBlock, sizeof(tag)); xorbuf(tag, partialBlock, sizeof(tag));
} }
if (ConstantCompare(authTag, tag, authTagSz) != 0) { /* Check authentication tag */
if (ConstantCompare(authTag, (byte*)tag, authTagSz) != 0) {
ret = AES_GCM_AUTH_E; ret = AES_GCM_AUTH_E;
} }