/** * @file HostCryptoAPIOpenSSL.c * @author NXP Semiconductors * @version 1.0 * @par License * * Copyright 2017 NXP * SPDX-License-Identifier: Apache-2.0 * * @par Description * Host Crypto OpenSSL wrapper implementation * * @par HISTORY * */ #include "HostCryptoAPI.h" //#include "ax_util.h" //#include "sm_types.h" #include #include #include #ifdef OPENSSL #include #include #include #include #include #include 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_NOT_SUPPORTED; #ifndef HLSE_IGNORE_PARAM_CHECK if (key == NULL || inData == NULL || outData == NULL || outDatalen == NULL) { return HLSE_ERR_API_ERROR; } #endif 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 || outEncryptedDataLen == NULL) { return HLSE_ERR_API_ERROR; } #endif // { Check if user requests to obtain the length only if (outEncryptedData == NULL) { if ((pMechanismType->mechanism == HLSE_AES_ECB_ENCRYPT) || (pMechanismType->mechanism == HLSE_AES_CBC_ENCRYPT)) { *outEncryptedDataLen = 16; return HLSE_SW_OK; } else if ((pMechanismType->mechanism == HLSE_DES_ECB_ENCRYPT) || (pMechanismType->mechanism == HLSE_DES_CBC_ENCRYPT)) { *outEncryptedDataLen = 8; return HLSE_SW_OK; } else { // type requested not found return HLSE_ERR_API_ERROR; } } // } end section obtaining only the length if (pMechanismType->mechanism == HLSE_AES_ECB_ENCRYPT) { AES_KEY keyLocal; int keyLenBits = inKeyLen * 8; int nRet = 0; // This works assuming the plaintext has the same size as the key // NOTE: AES_set_encrypt_key returns 0 upon success nRet = AES_set_encrypt_key(inKey, keyLenBits, &keyLocal); if (nRet != 0) { return HOST_CRYPTO_ERROR; } // AES_ecb_encrypt has return type void AES_ecb_encrypt(inData, outEncryptedData, &keyLocal, AES_ENCRYPT); return HOST_CRYPTO_OK; } else if (pMechanismType->mechanism == HLSE_AES_CBC_ENCRYPT) { // int outLen = 0; int nRet; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) EVP_CIPHER_CTX aesCtx; #else EVP_CIPHER_CTX *aesCtx = NULL; #endif int outEncryptedDataLenInt = (int)(*outEncryptedDataLen); #if (OPENSSL_VERSION_NUMBER < 0x10100000L) EVP_CIPHER_CTX_init(&aesCtx); #else aesCtx = EVP_CIPHER_CTX_new(); if (aesCtx == NULL) { return HOST_CRYPTO_ERROR; } #endif if (inKeyLen != AES_BLOCK_SIZE) { // printf("Unsupported key length for HOST_AES_CBC_Process\r\n"); return HLSE_ERR_API_ERROR; } // iv is passed in the pParameter if (pMechanismType->pParameter == NULL) { return HLSE_ERR_API_ERROR; } if ((inDataLen % AES_BLOCK_SIZE) != 0) { // printf("Input data are not block aligned for HOST_AES_CBC_Process\r\n"); return HLSE_ERR_API_ERROR; } #if (OPENSSL_VERSION_NUMBER < 0x10100000L) // EVP_EncryptInit_ex returns 0 on failure and 1 upon success if (!EVP_EncryptInit_ex(&aesCtx, EVP_aes_128_cbc(), NULL, inKey, pMechanismType->pParameter)) { return HOST_CRYPTO_ERROR; } if (!EVP_EncryptUpdate(&aesCtx, outEncryptedData, &outEncryptedDataLenInt, inData, inDataLen)) { *outEncryptedDataLen = (U32)outEncryptedDataLenInt; return HOST_CRYPTO_ERROR; } #else // EVP_EncryptInit_ex returns 0 on failure and 1 upon success if (!EVP_EncryptInit_ex(aesCtx, EVP_aes_128_cbc(), NULL, inKey, pMechanismType->pParameter)) { return HOST_CRYPTO_ERROR; } if (!EVP_EncryptUpdate(aesCtx, outEncryptedData, &outEncryptedDataLenInt, inData, inDataLen)) { *outEncryptedDataLen = (U32)outEncryptedDataLenInt; return HOST_CRYPTO_ERROR; } #endif *outEncryptedDataLen = (U32)outEncryptedDataLenInt; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) nRet = EVP_CIPHER_CTX_cleanup(&aesCtx); #else EVP_CIPHER_CTX_free(aesCtx); nRet = 1; #endif return nRet; } else if (pMechanismType->mechanism == HLSE_DES_ECB_ENCRYPT) { int nRet = 0; // DES_cblock key1, key2, key3; DES_key_schedule ks1, ks2, ks3; U32 i; if (inKeyLen >= 8) { nRet = DES_set_key((DES_cblock *)inKey, &ks1); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen >= 16) { nRet = DES_set_key((DES_cblock *)(&inKey[8]), &ks2); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen == 24) { nRet = DES_set_key((DES_cblock *)(&inKey[16]), &ks3); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } for (i = 0; i < inDataLen; i += 8) { if (inKeyLen == 24) { DES_ecb3_encrypt((DES_cblock *)(inData + i), (DES_cblock *)(outEncryptedData + i), &ks1, &ks2, &ks3, DES_ENCRYPT); } else if (inKeyLen == 16) { DES_ecb2_encrypt((DES_cblock *)(inData + i), (DES_cblock *)(outEncryptedData + i), &ks1, &ks2, DES_ENCRYPT); } else { DES_ecb_encrypt((DES_cblock *)(inData + i), (DES_cblock *)(outEncryptedData + i), &ks1, DES_ENCRYPT); } } return HOST_CRYPTO_OK; } else if (pMechanismType->mechanism == HLSE_DES_CBC_ENCRYPT) { int nRet = 0; // DES_cblock key1, key2, key3; DES_key_schedule ks1, ks2, ks3; // iv is passed in the pParameter if (pMechanismType->pParameter == NULL) { return HLSE_ERR_API_ERROR; } if (inKeyLen >= 8) { nRet = DES_set_key((DES_cblock *)inKey, &ks1); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen >= 16) { nRet = DES_set_key((DES_cblock *)(&inKey[8]), &ks2); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen == 24) { nRet = DES_set_key((DES_cblock *)(&inKey[16]), &ks3); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen == 24) { DES_ede3_cbc_encrypt(inData, outEncryptedData, inDataLen, &ks1, &ks2, &ks3, pMechanismType->pParameter, DES_ENCRYPT); } else if (inKeyLen == 16) { DES_ede2_cbc_encrypt(inData, outEncryptedData, inDataLen, &ks1, &ks2, pMechanismType->pParameter, DES_ENCRYPT); } else { DES_cbc_encrypt(inData, outEncryptedData, inDataLen, &ks1, pMechanismType->pParameter, DES_ENCRYPT); } return HOST_CRYPTO_OK; } 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 || outDecryptedDataLen == NULL) { return HLSE_ERR_API_ERROR; } #endif // { Check if user requets to obtain the length only if (outDecryptedData == NULL) { if ((pMechanismType->mechanism == HLSE_AES_ECB_DECRYPT) || (pMechanismType->mechanism == HLSE_AES_CBC_DECRYPT)) { *outDecryptedDataLen = 16; return HLSE_SW_OK; } else if ((pMechanismType->mechanism == HLSE_DES_ECB_DECRYPT) || (pMechanismType->mechanism == HLSE_DES_CBC_DECRYPT)) { *outDecryptedDataLen = 8; return HLSE_SW_OK; } else { // type requested not found return HLSE_ERR_API_ERROR; } } // } end section obtaining only the length if (pMechanismType->mechanism == HLSE_AES_ECB_DECRYPT) { AES_KEY keyLocal; int keyLenBits = inKeyLen * 8; int nRet = 0; // This works assuming the plaintext has the same size as the key // NOTE: AES_set_encrypt_key returns 0 upon success nRet = AES_set_decrypt_key(inKey, keyLenBits, &keyLocal); if (nRet != 0) { return HOST_CRYPTO_ERROR; } // AES_ecb_encrypt has return type void AES_ecb_encrypt(inData, outDecryptedData, &keyLocal, AES_DECRYPT); return HOST_CRYPTO_OK; } else if (pMechanismType->mechanism == HLSE_AES_CBC_DECRYPT) { // int outLen = 0; int nRet; int outDecryptedDataLenInt = (int)(*outDecryptedDataLen); #if (OPENSSL_VERSION_NUMBER < 0x10100000L) EVP_CIPHER_CTX aesCtx; #else EVP_CIPHER_CTX *aesCtx = NULL; #endif #if (OPENSSL_VERSION_NUMBER < 0x10100000L) EVP_CIPHER_CTX_init(&aesCtx); #else aesCtx = EVP_CIPHER_CTX_new(); if (aesCtx == NULL) { return HOST_CRYPTO_ERROR; } #endif if (inKeyLen != AES_BLOCK_SIZE) { // printf("Unsupported key length for HOST_AES_CBC_Process\r\n"); return HLSE_ERR_API_ERROR; } // iv is passed in the pParameter if (pMechanismType->pParameter == NULL) { return HLSE_ERR_API_ERROR; } if ((inDataLen % AES_BLOCK_SIZE) != 0) { // printf("Input data are not block aligned for HOST_AES_CBC_Process\r\n"); return HLSE_ERR_API_ERROR; } #if (OPENSSL_VERSION_NUMBER < 0x10100000L) // EVP_EncryptInit_ex returns 0 on failure and 1 upon success if (!EVP_DecryptInit_ex(&aesCtx, EVP_aes_128_cbc(), NULL, inKey, pMechanismType->pParameter)) { return HOST_CRYPTO_ERROR; } if (!EVP_DecryptUpdate(&aesCtx, outDecryptedData, &outDecryptedDataLenInt, inData, inDataLen)) { *outDecryptedDataLen = outDecryptedDataLenInt; return HOST_CRYPTO_ERROR; } #else // EVP_EncryptInit_ex returns 0 on failure and 1 upon success if (!EVP_DecryptInit_ex(aesCtx, EVP_aes_128_cbc(), NULL, inKey, pMechanismType->pParameter)) { return HOST_CRYPTO_ERROR; } if (!EVP_DecryptUpdate(aesCtx, outDecryptedData, &outDecryptedDataLenInt, inData, inDataLen)) { *outDecryptedDataLen = outDecryptedDataLenInt; return HOST_CRYPTO_ERROR; } #endif *outDecryptedDataLen = outDecryptedDataLenInt; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) nRet = EVP_CIPHER_CTX_cleanup(&aesCtx); #else EVP_CIPHER_CTX_free(aesCtx); nRet = 1; #endif return nRet; } else if (pMechanismType->mechanism == HLSE_DES_ECB_DECRYPT) { int nRet = 0; // DES_cblock key1, key2, key3; DES_key_schedule ks1, ks2, ks3; U32 i; if (inKeyLen >= 8) { nRet = DES_set_key((DES_cblock *)inKey, &ks1); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen >= 16) { nRet = DES_set_key((DES_cblock *)(&inKey[8]), &ks2); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen == 24) { nRet = DES_set_key((DES_cblock *)(&inKey[16]), &ks3); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } for (i = 0; i < inDataLen; i += 8) { if (inKeyLen == 24) { DES_ecb3_encrypt((DES_cblock *)(inData + i), (DES_cblock *)(outDecryptedData + i), &ks1, &ks2, &ks3, DES_DECRYPT); } else if (inKeyLen == 16) { DES_ecb2_encrypt((DES_cblock *)(inData + i), (DES_cblock *)(outDecryptedData + i), &ks1, &ks2, DES_DECRYPT); } else { DES_ecb_encrypt((DES_cblock *)(inData + i), (DES_cblock *)(outDecryptedData + i), &ks1, DES_DECRYPT); } } return HOST_CRYPTO_OK; } else if (pMechanismType->mechanism == HLSE_DES_CBC_DECRYPT) { int nRet = 0; // DES_cblock key1, key2, key3; DES_key_schedule ks1, ks2, ks3; // iv is passed in the pParameter if (pMechanismType->pParameter == NULL) { return HLSE_ERR_API_ERROR; } if (inKeyLen >= 8) { nRet = DES_set_key((DES_cblock *)inKey, &ks1); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen >= 16) { nRet = DES_set_key((DES_cblock *)(&inKey[8]), &ks2); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen == 24) { nRet = DES_set_key((DES_cblock *)(&inKey[16]), &ks3); if (nRet != 0) { return HOST_CRYPTO_ERROR; } } if (inKeyLen == 24) { DES_ede3_cbc_encrypt(inData, outDecryptedData, inDataLen, &ks1, &ks2, &ks3, pMechanismType->pParameter, DES_DECRYPT); } else if (inKeyLen == 16) { DES_ede2_cbc_encrypt(inData, outDecryptedData, inDataLen, &ks1, &ks2, pMechanismType->pParameter, DES_DECRYPT); } else { DES_cbc_encrypt(inData, outDecryptedData, inDataLen, &ks1, pMechanismType->pParameter, DES_DECRYPT); } return HOST_CRYPTO_OK; } return HLSE_ERR_API_ERROR; } HLSE_RET_CODE HLCRYPT_Digest(HLSE_MECHANISM_INFO* pMechanismType, U8* inData, U32 inDataLen, U8* outDigest, U32* outDigestLen) { #ifndef HLSE_IGNORE_PARAM_CHECK if (pMechanismType == NULL || inData == NULL || outDigestLen == NULL) { return HLSE_ERR_API_ERROR; } #endif // Check for a request for digest Len if (outDigest == NULL) { if (pMechanismType->mechanism == HLSE_SHA256) { *outDigestLen = 32; return HLSE_SW_OK; } else if (pMechanismType->mechanism == HLSE_SHA1) { *outDigestLen = 20; return HLSE_SW_OK; } else { return HLSE_ERR_API_ERROR; } } if (pMechanismType->mechanism == HLSE_SHA256) { SHA256_CTX ctx256; int ret; ret = SHA256_Init(&ctx256); if (ret == HOST_CRYPTO_OK) { ret = SHA256_Update(&ctx256, inData, inDataLen); if (ret == HOST_CRYPTO_OK) { ret = SHA256_Final(outDigest, &ctx256); *outDigestLen = 32; } } return ret; } else if (pMechanismType->mechanism == HLSE_SHA1) { SHA_CTX ctx; int ret; ret = SHA1_Init(&ctx); if (ret == HOST_CRYPTO_OK) { ret = SHA1_Update(&ctx, inData, inDataLen); if (ret == HOST_CRYPTO_OK) { ret = SHA1_Final(outDigest, &ctx); *outDigestLen = 20; } } return ret; } return HLSE_ERR_API_ERROR; } static S32 HOST_CMAC_Init_Des(CMAC_CTX **ctx, const U8 *pKey, U8 keySizeInBytes) { int ret; *ctx = CMAC_CTX_new(); if (*ctx == NULL) { return HLSE_ERR_API_ERROR; } // CMAC_Init() returns // 1 = success // 0 = failure ret = CMAC_Init(*ctx, pKey, keySizeInBytes, EVP_des_ede3_cbc(), NULL); return ret; } 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 || outSignatureLen == NULL) { return HLSE_ERR_API_ERROR; } #endif // Check for a request to get the required signature len if (outSignature == NULL) { if (pMechanismType->mechanism == HLSE_AES_CMAC) { *outSignatureLen = 16; // AES_KEY_LEN_nBYTE return HLSE_SW_OK; } else { return HLSE_ERR_API_ERROR; } } if (pMechanismType->mechanism == HLSE_AES_CMAC) { int ret; CMAC_CTX *ctx; size_t outSignatureLenSizeT = (size_t)(*outSignatureLen); ctx = CMAC_CTX_new(); if (ctx == NULL) { return HLSE_ERR_API_ERROR; } // CMAC_Init() returns // 1 = success // 0 = failure ret = CMAC_Init(ctx, inKey, inKeyLen, EVP_aes_128_cbc(), NULL); if (ret == HOST_CRYPTO_OK) { ret = CMAC_Update(ctx, inData, inDataLen); if (ret == HOST_CRYPTO_OK) { ret = CMAC_Final(ctx, outSignature, &outSignatureLenSizeT); *outSignatureLen = (U32)outSignatureLenSizeT; } } if (ret != HLSE_ERR_MEMORY) { CMAC_CTX_free(ctx); } return ret; } else if (pMechanismType->mechanism == HLSE_DES_CMAC) { int ret; size_t size; CMAC_CTX *ctx; ret = HOST_CMAC_Init_Des(&ctx, inKey, inKeyLen); if (ret == HOST_CRYPTO_OK) { ret = CMAC_Update(ctx, inData, inDataLen); if (ret == HOST_CRYPTO_OK) { ret = CMAC_Final(ctx, outSignature, &size); } } if (ret != HLSE_ERR_MEMORY) { CMAC_CTX_free(ctx); } return ret; } else if (pMechanismType->mechanism == HLSE_ECDSA_SIGN) { unsigned int lclOutSignatureLen = (unsigned int)(*outSignatureLen); int status; status = ECDSA_sign(0, inData, inDataLen, outSignature, &lclOutSignatureLen, (EC_KEY *)inKey); *outSignatureLen = lclOutSignatureLen; if (status == 1) { return HLSE_SW_OK; } else { return HLSE_ERR_CRYPTO_ENGINE_FAILED; } } 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 = ECDSA_verify(0, inData, inDataLen, inSignature, inSignatureLen, (EC_KEY *)inKey); if (status == 1) { 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; *hContext = CMAC_CTX_new(); if (*hContext == NULL) { return HLSE_ERR_MEMORY; } // CMAC_Init() returns // 1 = success // 0 = failure ret = CMAC_Init(*hContext, inKey, inKeyLen, EVP_aes_128_cbc(), NULL); return ret; } 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 // CMAC_Update() returns // 1 = success // 0 = failure ret = CMAC_Update(hContext, inDataPart, inDataPartLen); return ret; } HLSE_RET_CODE HLCRYPT_SignFinal(HLSE_CONTEXT_HANDLE hContext, U8* outSignature, U32* outSignatureLen) { int ret; size_t outSignatureLenSizeT; #ifndef HLSE_IGNORE_PARAM_CHECK if (outSignatureLen == NULL) { return HLSE_ERR_API_ERROR; } #endif outSignatureLenSizeT = (size_t)(*outSignatureLen); // Check for a request to get the required signature len if (outSignature == NULL) { *outSignatureLen = 16; return HLSE_SW_OK; } // CMAC_Final() returns // 1 = success // 0 = failure ret = CMAC_Final(hContext, outSignature, &outSignatureLenSizeT); *outSignatureLen = (U32)outSignatureLenSizeT; CMAC_CTX_free(hContext); return ret; } HLSE_RET_CODE HLCRYPT_GetRandom(U32 inLen, U8 * pRandom) { int nRet; #ifndef HLSE_IGNORE_PARAM_CHECK if (pRandom == NULL) { return HLSE_ERR_API_ERROR; } #endif nRet = RAND_bytes(pRandom, inLen); return nRet; } #endif // OPENSSL