| /** | |
| * @file HostCryptoAPImbedtls.c | |
| * @author NXP Semiconductors | |
| * @version 1.0 | |
| * @par License | |
| * | |
| * Copyright 2017 NXP | |
| * SPDX-License-Identifier: Apache-2.0 | |
| * | |
| * @par Description | |
| * Host Crypto mbed TLS wrapper implementation | |
| * | |
| * @par HISTORY | |
| * | |
| */ | |
| #include "HostCryptoAPI.h" | |
| //#include "ax_util.h" | |
| //#include "sm_types.h" | |
| #include <assert.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <mbedtls/aes.h> | |
| #include <mbedtls/des.h> | |
| #include <mbedtls/ctr_drbg.h> | |
| #include <mbedtls/entropy.h> | |
| #ifdef MBEDTLS_CMAC_C | |
| # include <mbedtls/cmac.h> | |
| #endif | |
| #include <mbedtls/cipher.h> | |
| #include <mbedtls/ecdsa.h> | |
| #include <mbedtls/pk.h> | |
| #include <mbedtls/entropy_poll.h> | |
| /*TODO check return paths and framework specified terminate paths are met */ | |
| #define AES_BLOCK_SIZE 16 /*TODO check if this can come from mbedtls */ | |
| static mbedtls_cipher_context_t cipher_ctx; | |
| HLSE_RET_CODE HLCRYPT_GetSupportedMechanisms(HLSE_MECHANISM_TYPE* mechanism, U32* mechanismLen) | |
| { | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (mechanismLen == NULL) | |
| return HLSE_ERR_API_ERROR; | |
| #endif | |
| if (mechanism == NULL) { | |
| *mechanismLen = 11; | |
| return HLSE_SW_OK; | |
| } | |
| if (mechanism != NULL && mechanismLen != NULL && *mechanismLen < 11) { | |
| *mechanismLen = 11; | |
| return HLSE_ERR_BUF_TOO_SMALL; | |
| } | |
| *mechanismLen = 11; | |
| *mechanism++ = HLSE_SHA1; | |
| *mechanism++ = HLSE_SHA256; | |
| *mechanism++ = HLSE_AES_CMAC; | |
| *mechanism++ = HLSE_AES_ECB_ENCRYPT; | |
| *mechanism++ = HLSE_AES_ECB_DECRYPT; | |
| *mechanism++ = HLSE_AES_CBC_ENCRYPT; | |
| *mechanism++ = HLSE_AES_CBC_DECRYPT; | |
| *mechanism++ = HLSE_DES_ECB_ENCRYPT; | |
| *mechanism++ = HLSE_DES_ECB_DECRYPT; | |
| *mechanism++ = HLSE_DES_CBC_ENCRYPT; | |
| *mechanism++ = HLSE_DES_CBC_DECRYPT; | |
| return HLSE_SW_OK; | |
| } | |
| HLSE_RET_CODE HLCRYPT_Single_DES_CBC_Encrypt(U8 *key, U32 keylen, | |
| U8 *iv, | |
| U16 ivlen, | |
| U8 *inData, | |
| U32 inDatalen, | |
| U8 * outData, | |
| U32 *outDatalen) | |
| { | |
| int nRet = HOST_CRYPTO_OK; | |
| int mbedtls_ret; | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (key == NULL || inData == NULL || outData == NULL || outDatalen == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| mbedtls_des_context ctx; | |
| mbedtls_des_init(&ctx); | |
| mbedtls_ret = mbedtls_des_setkey_enc(&ctx, key); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| } | |
| mbedtls_ret = mbedtls_des_crypt_cbc(&ctx, | |
| MBEDTLS_DES_ENCRYPT, | |
| inDatalen, | |
| iv, | |
| inData, | |
| outData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| } | |
| mbedtls_des_free(&ctx); | |
| return nRet; | |
| } | |
| HLSE_RET_CODE HLCRYPT_Encrypt(HLSE_MECHANISM_INFO* pMechanismType, U8* inKey, U32 inKeyLen, | |
| U8* inData, U32 inDataLen, | |
| U8* outEncryptedData, U32* outEncryptedDataLen) | |
| { | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (pMechanismType == NULL || inKey == NULL || inData == NULL || outEncryptedData == NULL || outEncryptedDataLen == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| if (pMechanismType->mechanism == HLSE_AES_ECB_ENCRYPT) { | |
| for (;;) { | |
| mbedtls_aes_context ctx; | |
| int keyLenBits = inKeyLen * 8; | |
| int nRet = HOST_CRYPTO_OK; | |
| int mbedtls_ret; | |
| mbedtls_aes_init(&ctx); | |
| // This works assuming the plaintext has the same size as the key | |
| // NOTE: AES_set_encrypt_key returns 0 upon success | |
| mbedtls_ret = mbedtls_aes_setkey_enc(&ctx, inKey, keyLenBits); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, inData, outEncryptedData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_aes_free(&ctx); | |
| return nRet; | |
| } | |
| } | |
| else if (pMechanismType->mechanism == HLSE_AES_CBC_ENCRYPT) { | |
| for (;;) { | |
| int nRet = HOST_CRYPTO_OK; | |
| int mbedtls_ret; | |
| int keyLenBits = inKeyLen * 8; | |
| mbedtls_aes_context ctx; | |
| unsigned char * pIv = (unsigned char *)pMechanismType->pParameter; | |
| mbedtls_aes_init(&ctx); | |
| mbedtls_ret = mbedtls_aes_setkey_enc(&ctx, inKey, keyLenBits); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_ENCRYPT, inDataLen, pIv, inData, outEncryptedData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_aes_free(&ctx); | |
| return nRet; | |
| } | |
| } | |
| else if (pMechanismType->mechanism == HLSE_DES_CBC_ENCRYPT) { | |
| for (;;) { | |
| int nRet = HOST_CRYPTO_OK; | |
| int mbedtls_ret; | |
| //int keyLenBits = inKeyLen * 8; | |
| mbedtls_des3_context ctx; | |
| unsigned char * pIv = (unsigned char *)pMechanismType->pParameter; | |
| mbedtls_des3_init(&ctx); | |
| mbedtls_ret = mbedtls_des3_set2key_enc(&ctx, inKey); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_ret = mbedtls_des3_crypt_cbc(&ctx, MBEDTLS_DES_ENCRYPT, inDataLen, pIv, inData, outEncryptedData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_des3_free(&ctx); | |
| return nRet; | |
| } | |
| } | |
| else if (pMechanismType->mechanism == HLSE_DES_ECB_ENCRYPT) { | |
| for (;;) { | |
| int nRet = HOST_CRYPTO_OK; | |
| int mbedtls_ret; | |
| mbedtls_des_context ctx; | |
| mbedtls_des_init(&ctx); | |
| mbedtls_ret = mbedtls_des_setkey_enc(&ctx, inKey); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_ret = mbedtls_des_crypt_ecb(&ctx, inData, outEncryptedData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_des_free(&ctx); | |
| return nRet; | |
| } | |
| } | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| HLSE_RET_CODE HLCRYPT_Decrypt(HLSE_MECHANISM_INFO* pMechanismType, U8* inKey, U32 inKeyLen, | |
| U8* inData, U32 inDataLen, | |
| U8* outDecryptedData, U32* outDecryptedDataLen) | |
| { | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (pMechanismType == NULL || inKey == NULL || inData == NULL || outDecryptedData == NULL || outDecryptedDataLen == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| if (pMechanismType->mechanism == HLSE_AES_ECB_DECRYPT) { | |
| for (;;) { | |
| mbedtls_aes_context ctx; | |
| int keyLenBits = inKeyLen * 8; | |
| int mbedtls_ret; | |
| int nRet = HOST_CRYPTO_OK; | |
| mbedtls_aes_init(&ctx); | |
| // This works assuming the plaintext has the same size as the key | |
| // NOTE: AES_set_encrypt_key returns 0 upon success | |
| mbedtls_ret = mbedtls_aes_setkey_dec(&ctx, inKey, keyLenBits); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| // AES_ecb_encrypt has return type void | |
| mbedtls_ret = mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, inData, outDecryptedData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_aes_free(&ctx); | |
| return nRet; | |
| } | |
| } | |
| else if (pMechanismType->mechanism == HLSE_AES_CBC_DECRYPT) { | |
| for (;;) { | |
| int nRet = HOST_CRYPTO_OK; | |
| int mbedtls_ret; | |
| int keyLenBits = inKeyLen * 8; | |
| unsigned char * pIv = (unsigned char *)pMechanismType->pParameter; | |
| mbedtls_aes_context ctx; | |
| mbedtls_aes_init(&ctx); | |
| if (inKeyLen != AES_BLOCK_SIZE) { | |
| // printf("Unsupported key length for HOST_AES_CBC_Process\r\n"); | |
| nRet = HLSE_ERR_API_ERROR; | |
| break; | |
| } | |
| // iv is passed in the pParameter | |
| if (pMechanismType->pParameter == NULL) { | |
| nRet = HLSE_ERR_API_ERROR; | |
| break; | |
| } | |
| if ((inDataLen % AES_BLOCK_SIZE) != 0) { | |
| // printf("Input data are not block aligned for HOST_AES_CBC_Process\r\n"); | |
| nRet = HLSE_ERR_API_ERROR; | |
| break; | |
| } | |
| // EVP_EncryptInit_ex returns 0 on failure and 1 upon success | |
| mbedtls_ret = mbedtls_aes_setkey_dec(&ctx, inKey, keyLenBits); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_ret = mbedtls_aes_crypt_cbc(&ctx, MBEDTLS_AES_DECRYPT, inDataLen, pIv, inData, outDecryptedData); | |
| if (mbedtls_ret != 0) | |
| { | |
| nRet = HOST_CRYPTO_ERROR; | |
| break; | |
| } | |
| mbedtls_aes_free(&ctx); | |
| return nRet; | |
| } | |
| } | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| HLSE_RET_CODE HLCRYPT_Digest(HLSE_MECHANISM_INFO* pMechanismType, | |
| U8* inData, U32 inDataLen, | |
| U8* outDigest, U32* outDigestLen) | |
| { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| HLSE_RET_CODE HLCRYPT_Sign(HLSE_MECHANISM_INFO* pMechanismType, U8* inKey, U32 inKeyLen, | |
| U8* inData, U32 inDataLen, | |
| U8* outSignature, U32* outSignatureLen) | |
| { | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (pMechanismType == NULL || inKey == NULL || inData == NULL || outSignature == NULL || outSignatureLen == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| if (pMechanismType->mechanism == HLSE_AES_CMAC) { | |
| int ret; | |
| //mbedtls_cipher_context_t cipher_ctx; | |
| const mbedtls_cipher_info_t *cipher_info; | |
| /*TODO CHECK mbedtls cmac does not suppot cbc but only ecb. mbedtls_cipher_cmac_starts returns error */ | |
| cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); | |
| if (cipher_info != NULL) | |
| { | |
| mbedtls_cipher_init(&cipher_ctx); | |
| ret = mbedtls_cipher_setup(&cipher_ctx, cipher_info); | |
| if (ret == 0) | |
| { | |
| #ifdef MBEDTLS_CMAC_C | |
| ret = mbedtls_cipher_cmac_starts(&cipher_ctx, inKey, (inKeyLen * 8)); | |
| if (ret == 0) | |
| { | |
| ret = mbedtls_cipher_cmac_update(&cipher_ctx, inData, inDataLen); | |
| if (ret == 0) | |
| { | |
| ret = mbedtls_cipher_cmac_finish(&cipher_ctx, outSignature); | |
| if (ret == 0) | |
| { | |
| ret = HOST_CRYPTO_OK; | |
| } | |
| } | |
| } | |
| #else | |
| ret = 1; | |
| #endif | |
| } | |
| mbedtls_cipher_free(&cipher_ctx); | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| return ret; | |
| } | |
| else if (pMechanismType->mechanism == HLSE_ECDSA_SIGN) | |
| { | |
| int status; | |
| size_t sigLen = *outSignatureLen; | |
| status = (mbedtls_ecdsa_write_signature(mbedtls_pk_ec(*(mbedtls_pk_context *)inKey), MBEDTLS_MD_SHA256, | |
| inData, inDataLen, | |
| outSignature, &sigLen, | |
| NULL, | |
| NULL)); | |
| *outSignatureLen = sigLen; | |
| if (status == 0) | |
| { | |
| return HLSE_SW_OK; | |
| } | |
| else | |
| { | |
| return HLSE_ERR_CRYPTO_ENGINE_FAILED; | |
| } | |
| } | |
| else | |
| { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| } | |
| HLSE_RET_CODE HLCRYPT_Verify(HLSE_MECHANISM_INFO* pMechanismType, U8* inKey, U32 inKeyLen, | |
| U8* inData, U32 inDataLen, | |
| U8* inSignature, U32 inSignatureLen) | |
| { | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (pMechanismType == NULL || inKey == NULL || inData == NULL || inSignature == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| if (pMechanismType->mechanism == HLSE_ECDSA_VERIFY) | |
| { | |
| int status; | |
| status = (mbedtls_ecdsa_read_signature(mbedtls_pk_ec(*(mbedtls_pk_context *)inKey), | |
| inData, inDataLen, | |
| inSignature, inSignatureLen)); | |
| if (status == 0) | |
| { | |
| return HLSE_SW_OK; | |
| } | |
| else | |
| { | |
| return HLSE_ERR_CRYPTO_ENGINE_FAILED; | |
| } | |
| } | |
| else | |
| { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| } | |
| HLSE_RET_CODE HLCRYPT_SignInit(HLSE_MECHANISM_INFO* pMechanismType, U8* inKey, U32 inKeyLen, HLSE_CONTEXT_HANDLE* hContext) | |
| { | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (pMechanismType == NULL || inKey == NULL || hContext == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| if (pMechanismType->mechanism == HLSE_AES_CMAC) { | |
| int ret; | |
| const mbedtls_cipher_info_t *cipher_info; | |
| *hContext = &cipher_ctx; | |
| /*TODO CHECK mbedtls cmac does not suppot cbc but only ecb. mbedtls_cipher_cmac_starts returns error */ | |
| cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB); | |
| if (cipher_info != NULL) | |
| { | |
| mbedtls_cipher_init(*hContext); | |
| ret = mbedtls_cipher_setup(*hContext, cipher_info); | |
| if (ret == 0) | |
| { | |
| #ifdef MBEDTLS_CMAC_C | |
| ret = mbedtls_cipher_cmac_starts(*hContext, inKey, (inKeyLen * 8)); | |
| #else | |
| ret = 1; | |
| #endif | |
| if (ret == 0) | |
| { | |
| ret = HOST_CRYPTO_OK; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| return 0; | |
| } | |
| return ret; | |
| } | |
| else | |
| { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| } | |
| HLSE_RET_CODE HLCRYPT_SignUpdate(HLSE_CONTEXT_HANDLE hContext, U8* inDataPart, U32 inDataPartLen) | |
| { | |
| int ret; | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (inDataPart == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| #ifdef MBEDTLS_CMAC_C | |
| ret = mbedtls_cipher_cmac_update(hContext, inDataPart, inDataPartLen); | |
| #else | |
| ret = 1; | |
| #endif | |
| if (ret == 0) | |
| { | |
| ret = HOST_CRYPTO_OK; | |
| } | |
| return ret; | |
| } | |
| HLSE_RET_CODE HLCRYPT_SignFinal(HLSE_CONTEXT_HANDLE hContext, U8* outSignature, U32* outSignatureLen) | |
| { | |
| int ret; | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (outSignature == NULL || outSignatureLen == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| #ifdef MBEDTLS_CMAC_C | |
| ret = mbedtls_cipher_cmac_finish(hContext, outSignature); | |
| #else | |
| ret = 1; | |
| #endif | |
| if (ret == 0) | |
| { | |
| ret = HOST_CRYPTO_OK; | |
| } | |
| mbedtls_cipher_free(hContext); | |
| return ret; | |
| } | |
| HLSE_RET_CODE HLCRYPT_GetRandom(U32 inLen, U8 * pRandom) | |
| { | |
| int nRet; | |
| #if AX_EMBEDDED | |
| size_t olen = 0; | |
| #elif defined( MBEDTLS_CTR_DRBG_C) | |
| mbedtls_entropy_context entropy; | |
| mbedtls_ctr_drbg_context ctr_drbg; | |
| #endif | |
| #ifndef HLSE_IGNORE_PARAM_CHECK | |
| if (pRandom == NULL) { | |
| return HLSE_ERR_API_ERROR; | |
| } | |
| #endif | |
| #if AX_EMBEDDED | |
| mbedtls_hardware_poll(NULL, pRandom, inLen, &olen); | |
| nRet = HOST_CRYPTO_OK; | |
| #elif defined( MBEDTLS_CTR_DRBG_C) | |
| mbedtls_entropy_init(&entropy); | |
| mbedtls_ctr_drbg_init(&ctr_drbg); | |
| nRet = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, | |
| NULL, | |
| 0); | |
| if (nRet == 0) | |
| { | |
| nRet = mbedtls_ctr_drbg_random((void*)&ctr_drbg, pRandom, inLen); | |
| if (nRet == 0) | |
| { | |
| nRet = HOST_CRYPTO_OK; | |
| } | |
| } | |
| #else | |
| nRet = HOST_CRYPTO_ERROR; | |
| #endif | |
| return nRet; | |
| } |