Topic: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hello,

I am using openssl 1.1.1f on Ubunutu.
I want to connect to an embedded device STM32H753 with wolfSSL.
I am using the HAL Library to use the crypto accelerators of the controller.
When I use the Software Implementation of AES the Handshake is working.
But when I am using the wc_AesGcmDecrypt_STM32 and wc_AesGcmEncrypt_STM32-function the Handshake is not working.

The Authentication Tag is wrong:
status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag,
            STM32_HAL_TIMEOUT);
           
The result of this function is wrong.

The HAL_CRYP_Encrypt and HAL_CRYP_Decrypt functions are working correct.

When I replace
HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag,
            STM32_HAL_TIMEOUT);
with
GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
                wc_AesEncrypt(aes, (byte*)ctrInit, (byte*)tag);
                xorbuf(authTag, tag, authTagSz);
               
The Handshake is working.

           
in wc_AesGcmEncrypt_STM32

Can you tell me why the Authentication tag is wrong when I use the HAL-Library?
Let me know when you need more information to solve this issue!

Thank you,

Andreas

Not working:

/* this function supports inline encrypt */
static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz,
                                  const byte* iv, word32 ivSz,
                                  byte* authTag, word32 authTagSz,
                                  const byte* authIn, word32 authInSz)
{
    int ret;
#ifdef WOLFSSL_STM32_CUBEMX
    CRYP_HandleTypeDef hcryp;
#else
    word32 keyCopy[AES_256_KEY_SIZE/sizeof(word32)];
#endif
    word32 keySize;
#ifdef WOLFSSL_STM32_CUBEMX
    int status = HAL_OK;
    word32 blocks = sz / AES_BLOCK_SIZE;
    word32 partialBlock[AES_BLOCK_SIZE/sizeof(word32)];
#else
    int status = SUCCESS;
#endif
    word32 partial = sz % AES_BLOCK_SIZE;
    word32 tag[AES_BLOCK_SIZE/sizeof(word32)];
    //word32 tag1[AES_BLOCK_SIZE/sizeof(word32)];
    word32 ctrInit[AES_BLOCK_SIZE/sizeof(word32)];
    word32 ctr[AES_BLOCK_SIZE/sizeof(word32)];
    word32 authhdr[AES_BLOCK_SIZE/sizeof(word32)];
    byte* authInPadded = NULL;
    int authPadSz, wasAlloc = 0;

    ret = wc_AesGetKeySize(aes, &keySize);
    if (ret != 0)
        return ret;

#ifdef WOLFSSL_STM32_CUBEMX
    ret = wc_Stm32_Aes_Init(aes, &hcryp);
    if (ret != 0)
        return ret;
#endif

    ret = wolfSSL_CryptHwMutexLock();
    if (ret != 0) {
        return ret;
    }

    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
    if (ivSz == GCM_NONCE_MID_SZ) {
        byte* pCtr = (byte*)ctr;
        XMEMCPY(ctr, iv, ivSz);
        pCtr[AES_BLOCK_SIZE - 1] = 1;
    }
    else {
        GHASH(aes, NULL, 0, iv, ivSz, (byte*)ctr, AES_BLOCK_SIZE);
    }
    XMEMCPY(ctrInit, ctr, sizeof(ctr)); /* save off initial counter for GMAC */

    /* Authentication buffer - must be 4-byte multiple zero padded */
    authPadSz = authInSz % sizeof(word32);
    if (authPadSz != 0) {
        authPadSz = authInSz + sizeof(word32) - authPadSz;
        if (authPadSz <= (int)sizeof(authhdr)) {
            authInPadded = (byte*)authhdr;
        }
        else {
            authInPadded = (byte*)XMALLOC(authPadSz, aes->heap,
                DYNAMIC_TYPE_TMP_BUFFER);
            if (authInPadded == NULL) {
                wolfSSL_CryptHwMutexUnLock();
                return MEMORY_E;
            }
            wasAlloc = 1;
        }
        XMEMSET(authInPadded, 0, authPadSz);
        XMEMCPY(authInPadded, authIn, authInSz);
    } else {
        authPadSz = authInSz;
        authInPadded = (byte*)authIn;
    }

    /* Hardware requires counter + 1 */
    IncrementGcmCounter((byte*)ctr);

#ifdef WOLFSSL_STM32_CUBEMX
    hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr;
    hcryp.Init.Header = (STM_CRYPT_TYPE*)authInPadded;

#if defined(STM32_HAL_V2)
    hcryp.Init.Algorithm  = CRYP_AES_GCM;
    hcryp.Init.HeaderSize = authPadSz/sizeof(word32);
    ByteReverseWords(partialBlock, ctr, AES_BLOCK_SIZE);
    hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock;
    HAL_CRYP_Init(&hcryp);

    /* 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);
    if (status == HAL_OK) {
        /* Compute the authTag */
        status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag,
            STM32_HAL_TIMEOUT);
    }
#elif defined(STM32_CRYPTO_AES_ONLY)
    /* Set the CRYP parameters */
    hcryp.Init.HeaderSize = authPadSz;
    if (authPadSz == 0)
        hcryp.Init.Header = NULL; /* cannot pass pointer here when authIn == 0 */
    hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_GCM_GMAC;
    hcryp.Init.OperatingMode = CRYP_ALGOMODE_ENCRYPT;
    hcryp.Init.GCMCMACPhase  = CRYP_INIT_PHASE;
    HAL_CRYP_Init(&hcryp);

    /* GCM init phase */
    status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
    if (status == HAL_OK) {
        /* GCM header phase */
        hcryp.Init.GCMCMACPhase = CRYP_HEADER_PHASE;
        status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
    }
    if (status == HAL_OK) {
        /* GCM payload phase - blocks */
        hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE;
        if (blocks) {
            status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)in,
                (blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT);
        }
    }
    if (status == HAL_OK && (partial != 0 || (sz > 0 && blocks == 0))) {
        /* GCM payload phase - partial remainder */
        XMEMSET(partialBlock, 0, sizeof(partialBlock));
        XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial);
        status = HAL_CRYPEx_AES_Auth(&hcryp, (uint8_t*)partialBlock, partial,
                (uint8_t*)partialBlock, STM32_HAL_TIMEOUT);
        XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial);
    }
    if (status == HAL_OK) {
        /* GCM final phase */
        hcryp.Init.GCMCMACPhase  = CRYP_FINAL_PHASE;
        status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, (uint8_t*)tag, STM32_HAL_TIMEOUT);
    }
#else
    hcryp.Init.HeaderSize = authPadSz;
    HAL_CRYP_Init(&hcryp);
    if (blocks) {
        /* GCM payload phase - blocks */
        status = HAL_CRYPEx_AESGCM_Encrypt(&hcryp, (byte*)in,
            (blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT);
    }
    if (status == HAL_OK && (partial != 0 || blocks == 0)) {
        /* GCM payload phase - partial remainder */
        XMEMSET(partialBlock, 0, sizeof(partialBlock));
        XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial);
        status = HAL_CRYPEx_AESGCM_Encrypt(&hcryp, (uint8_t*)partialBlock, partial,
            (uint8_t*)partialBlock, STM32_HAL_TIMEOUT);
        XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial);
    }
    if (status == HAL_OK) {
        /* Compute the authTag */
        status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, (uint8_t*)tag, STM32_HAL_TIMEOUT);
    }
#endif

    //if (status != HAL_OK)
    //    ret = AES_GCM_AUTH_E;
    HAL_CRYP_DeInit(&hcryp);

#else /* Standard Peripheral Library */
    ByteReverseWords(keyCopy, (word32*)aes->key, keySize);
    status = CRYP_AES_GCM(MODE_ENCRYPT, (uint8_t*)ctr,
                         (uint8_t*)keyCopy,      keySize * 8,
                         (uint8_t*)in,           sz,
                         (uint8_t*)authInPadded, authInSz,
                         (uint8_t*)out,          (uint8_t*)tag);
    if (status != SUCCESS)
        ret = AES_GCM_AUTH_E;
#endif /* WOLFSSL_STM32_CUBEMX */

    if (ret == 0) {
        /* return authTag */
        if (authTag) {//change to make it work
            /* For STM32 GCM fallback to software if partial AES block or IV != 12 */
            if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ) {
                GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
                wc_AesEncrypt(aes, (byte*)ctrInit, (byte*)tag);
                xorbuf(authTag, tag, authTagSz);
            }
            else {
                XMEMCPY(authTag, tag, authTagSz);
            }
        }
    }


    /* Free memory */
    if (wasAlloc) {
        XFREE(authInPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
    }

    wolfSSL_CryptHwMutexUnLock();

    return ret;
}

working:

/* this function supports inline encrypt */
static int wc_AesGcmEncrypt_STM32(Aes* aes, byte* out, const byte* in, word32 sz,
                                  const byte* iv, word32 ivSz,
                                  byte* authTag, word32 authTagSz,
                                  const byte* authIn, word32 authInSz)
{
    int ret;
#ifdef WOLFSSL_STM32_CUBEMX
    CRYP_HandleTypeDef hcryp;
#else
    word32 keyCopy[AES_256_KEY_SIZE/sizeof(word32)];
#endif
    word32 keySize;
#ifdef WOLFSSL_STM32_CUBEMX
    int status = HAL_OK;
    word32 blocks = sz / AES_BLOCK_SIZE;
    word32 partialBlock[AES_BLOCK_SIZE/sizeof(word32)];
#else
    int status = SUCCESS;
#endif
    word32 partial = sz % AES_BLOCK_SIZE;
    word32 tag[AES_BLOCK_SIZE/sizeof(word32)];
    //word32 tag1[AES_BLOCK_SIZE/sizeof(word32)];
    word32 ctrInit[AES_BLOCK_SIZE/sizeof(word32)];
    word32 ctr[AES_BLOCK_SIZE/sizeof(word32)];
    word32 authhdr[AES_BLOCK_SIZE/sizeof(word32)];
    byte* authInPadded = NULL;
    int authPadSz, wasAlloc = 0;

    ret = wc_AesGetKeySize(aes, &keySize);
    if (ret != 0)
        return ret;

#ifdef WOLFSSL_STM32_CUBEMX
    ret = wc_Stm32_Aes_Init(aes, &hcryp);
    if (ret != 0)
        return ret;
#endif

    ret = wolfSSL_CryptHwMutexLock();
    if (ret != 0) {
        return ret;
    }

    XMEMSET(ctr, 0, AES_BLOCK_SIZE);
    if (ivSz == GCM_NONCE_MID_SZ) {
        byte* pCtr = (byte*)ctr;
        XMEMCPY(ctr, iv, ivSz);
        pCtr[AES_BLOCK_SIZE - 1] = 1;
    }
    else {
        GHASH(aes, NULL, 0, iv, ivSz, (byte*)ctr, AES_BLOCK_SIZE);
    }
    XMEMCPY(ctrInit, ctr, sizeof(ctr)); /* save off initial counter for GMAC */

    /* Authentication buffer - must be 4-byte multiple zero padded */
    authPadSz = authInSz % sizeof(word32);
    if (authPadSz != 0) {
        authPadSz = authInSz + sizeof(word32) - authPadSz;
        if (authPadSz <= (int)sizeof(authhdr)) {
            authInPadded = (byte*)authhdr;
        }
        else {
            authInPadded = (byte*)XMALLOC(authPadSz, aes->heap,
                DYNAMIC_TYPE_TMP_BUFFER);
            if (authInPadded == NULL) {
                wolfSSL_CryptHwMutexUnLock();
                return MEMORY_E;
            }
            wasAlloc = 1;
        }
        XMEMSET(authInPadded, 0, authPadSz);
        XMEMCPY(authInPadded, authIn, authInSz);
    } else {
        authPadSz = authInSz;
        authInPadded = (byte*)authIn;
    }

    /* Hardware requires counter + 1 */
    IncrementGcmCounter((byte*)ctr);

#ifdef WOLFSSL_STM32_CUBEMX
    hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)ctr;
    hcryp.Init.Header = (STM_CRYPT_TYPE*)authInPadded;

#if defined(STM32_HAL_V2)
    hcryp.Init.Algorithm  = CRYP_AES_GCM;
    hcryp.Init.HeaderSize = authPadSz/sizeof(word32);
    ByteReverseWords(partialBlock, ctr, AES_BLOCK_SIZE);
    hcryp.Init.pInitVect = (STM_CRYPT_TYPE*)partialBlock;
    HAL_CRYP_Init(&hcryp);

    /* 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);
    if (status == HAL_OK) {
        /* Compute the authTag */
        //status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag,
        //    STM32_HAL_TIMEOUT);
    }
#elif defined(STM32_CRYPTO_AES_ONLY)
    /* Set the CRYP parameters */
    hcryp.Init.HeaderSize = authPadSz;
    if (authPadSz == 0)
        hcryp.Init.Header = NULL; /* cannot pass pointer here when authIn == 0 */
    hcryp.Init.ChainingMode  = CRYP_CHAINMODE_AES_GCM_GMAC;
    hcryp.Init.OperatingMode = CRYP_ALGOMODE_ENCRYPT;
    hcryp.Init.GCMCMACPhase  = CRYP_INIT_PHASE;
    HAL_CRYP_Init(&hcryp);

    /* GCM init phase */
    status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
    if (status == HAL_OK) {
        /* GCM header phase */
        hcryp.Init.GCMCMACPhase = CRYP_HEADER_PHASE;
        status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, 0, NULL, STM32_HAL_TIMEOUT);
    }
    if (status == HAL_OK) {
        /* GCM payload phase - blocks */
        hcryp.Init.GCMCMACPhase = CRYP_PAYLOAD_PHASE;
        if (blocks) {
            status = HAL_CRYPEx_AES_Auth(&hcryp, (byte*)in,
                (blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT);
        }
    }
    if (status == HAL_OK && (partial != 0 || (sz > 0 && blocks == 0))) {
        /* GCM payload phase - partial remainder */
        XMEMSET(partialBlock, 0, sizeof(partialBlock));
        XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial);
        status = HAL_CRYPEx_AES_Auth(&hcryp, (uint8_t*)partialBlock, partial,
                (uint8_t*)partialBlock, STM32_HAL_TIMEOUT);
        XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial);
    }
    if (status == HAL_OK) {
        /* GCM final phase */
        hcryp.Init.GCMCMACPhase  = CRYP_FINAL_PHASE;
        status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, (uint8_t*)tag, STM32_HAL_TIMEOUT);
    }
#else
    hcryp.Init.HeaderSize = authPadSz;
    HAL_CRYP_Init(&hcryp);
    if (blocks) {
        /* GCM payload phase - blocks */
        status = HAL_CRYPEx_AESGCM_Encrypt(&hcryp, (byte*)in,
            (blocks * AES_BLOCK_SIZE), out, STM32_HAL_TIMEOUT);
    }
    if (status == HAL_OK && (partial != 0 || blocks == 0)) {
        /* GCM payload phase - partial remainder */
        XMEMSET(partialBlock, 0, sizeof(partialBlock));
        XMEMCPY(partialBlock, in + (blocks * AES_BLOCK_SIZE), partial);
        status = HAL_CRYPEx_AESGCM_Encrypt(&hcryp, (uint8_t*)partialBlock, partial,
            (uint8_t*)partialBlock, STM32_HAL_TIMEOUT);
        XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial);
    }
    if (status == HAL_OK) {
        /* Compute the authTag */
        status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, (uint8_t*)tag, STM32_HAL_TIMEOUT);
    }
#endif

    //if (status != HAL_OK)
    //    ret = AES_GCM_AUTH_E;
    HAL_CRYP_DeInit(&hcryp);

#else /* Standard Peripheral Library */
    ByteReverseWords(keyCopy, (word32*)aes->key, keySize);
    status = CRYP_AES_GCM(MODE_ENCRYPT, (uint8_t*)ctr,
                         (uint8_t*)keyCopy,      keySize * 8,
                         (uint8_t*)in,           sz,
                         (uint8_t*)authInPadded, authInSz,
                         (uint8_t*)out,          (uint8_t*)tag);
    if (status != SUCCESS)
        ret = AES_GCM_AUTH_E;
#endif /* WOLFSSL_STM32_CUBEMX */

    if (ret == 0) {
        /* return authTag */
        if (authTag) {//change to make it work
            /* For STM32 GCM fallback to software if partial AES block or IV != 12 */
            //if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ) {
                GHASH(aes, authIn, authInSz, out, sz, authTag, authTagSz);
                wc_AesEncrypt(aes, (byte*)ctrInit, (byte*)tag);
                xorbuf(authTag, tag, authTagSz);
            //}
            //else {
                XMEMCPY(authTag, tag, authTagSz);
            //}
        }
    }


    /* Free memory */
    if (wasAlloc) {
        XFREE(authInPadded, aes->heap, DYNAMIC_TYPE_TMP_BUFFER);
    }

    wolfSSL_CryptHwMutexUnLock();

    return ret;
}

Share

Re: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hi AnMu5962,

The issue appears to be related to the AES GCM auth tag calculation. There are fixes for this and this has been tested recently.

Can you confirm you are using the latest wolfSSL master and the latest STM32 Cube MX pack for the H7? Are you using the `STM32_HAL_V2` build option?

If you are using the latest can you print out the "sz", "ivSz", "authTagSz" and "authInSz" being used?

Thanks,
David Garske, wolfSSL

Share

Re: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hi David,

Thank you for your fast response.
I am using the Version 4.5.0 of WolfSSL
I am using HAL_V2.

sz: 16
ivSz: 12
authTagSz: 16
authInSz: 13

This is in decrypt
wc_AesGcmDecrypt_STM32

This works:

byte counter[AES_BLOCK_SIZE];
    byte initialCounter[AES_BLOCK_SIZE];
    byte Tprime[AES_BLOCK_SIZE];
    byte EKY0[AES_BLOCK_SIZE];
    byte *ctr1;

    byte* authInPadded = NULL;
    int authPadSz, wasAlloc = 0;

    /* Use the Software Implementation to verify the auth-Tag */
    ctr1 = counter;
    XMEMSET(initialCounter, 0, AES_BLOCK_SIZE);
    if (ivSz == GCM_NONCE_MID_SZ) {
        XMEMCPY(initialCounter, iv, ivSz);
        initialCounter[AES_BLOCK_SIZE - 1] = 1;
    }

    XMEMCPY(ctr1, initialCounter, AES_BLOCK_SIZE);

    GHASH(aes, authIn, authInSz, in, sz, Tprime, sizeof(Tprime));
    wc_AesEncrypt(aes, ctr1, EKY0);
    xorbuf(Tprime, EKY0, sizeof(Tprime));

    if (ConstantCompare(authTag, Tprime, authTagSz) != 0) {
        ret = AES_GCM_AUTH_E;
    }

This not:

status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag,
           STM32_HAL_TIMEOUT);


Thank you,

Andreas

Share

Re: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hi Andreas,

I understand, one is using our wolfCrypt software to calculate the AES GCM HMAC. The other is using the STM hardware. Are you able to printout/capture the following variables in the failure case  "sz", "ivSz", "authTagSz" and "authInSz?

What is the version of the STM32 Cube MX Hal code you are using?

Thanks,
David Garske, wolfSSL

Share

Re: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hi David,

I am using the
@brief STM32H7xx HAL Driver version number V1.9.0
Version 1.9.0

Do you recommend me using another version.
sz: 16
ivSz: 12
authTagSz: 16
authInSz: 13

I get this in the failure case. There is no difference.
They are not changed by:
status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag,
           STM32_HAL_TIMEOUT);

Thanks,

Andreas

Share

Re: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hi Andreas,

Can you please try updating to the latest wolfSSL GitHub master? There are fixes in since v4.5.0 in aes.c for these STM32 functions.

The latest STM32 Cube MX HAL version I can find is v1.8. I ran our TLS cipher suite test on the H753ZI board with AES crypto hardware acceleration enabled and could not reproduce an issue.

Here is the example I am using:
https://drive.google.com/file/d/1-RIGxq … sp=sharing

Thanks,
David Garske, wolfSSL

Share

Re: WolfSSL Handshake Problem with HAL-Library of STM32H753

Hi David,

I know that the test case is working, I have tried it too.
I get this issue at the Handshake of wolfssl and openssl.
Can you tell me why.
I am using the newest wolfssl Version and I think I have the same Version of HAL as you.

Thank you,

Andreas

Share