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;
}