/* * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "huks_aes_adapter.h" #include #include "hks_api.h" #include "securec.h" #include "intell_voice_log.h" #include "scope_guard.h" #define LOG_TAG "HuksAesAdapter" using namespace std; namespace OHOS { namespace IntellVoiceUtils { static char g_aliasName[] = "IntelligentVoiceKey"; static char g_aadValue[] = "IntelligentVoiceAAD"; static constexpr uint32_t MAX_UPDATE_SIZE = 64 * 1024; static constexpr uint32_t MAX_OUTDATA_SIZE = 128 * 1024; static constexpr uint32_t NONCE_SIZE = 12; static constexpr uint32_t AEAD_SIZE = 16; static struct HksParam g_existParams[] = { { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE } }; static struct HksParam g_genParams[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT | HKS_KEY_PURPOSE_DECRYPT }, { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_128 }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE } }; int32_t HuksAesAdapter::CreateEncryptParamSet(struct HksParamSet **encryptParamSet, struct HksBlob *encryptNonce) { int32_t ret = HksGenerateRandom(nullptr, encryptNonce); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("generate random encrypt nonce failed, ret:%{public}d", ret); return ret; } struct HksParam encryptParams[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_ENCRYPT }, { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_128 }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_NONE }, { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = { .size = static_cast(strlen(g_aadValue)), .data = reinterpret_cast(g_aadValue) } }, { .tag = HKS_TAG_NONCE, .blob = { .size = encryptNonce->size, .data = encryptNonce->data } }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE } }; ret = ConstructParamSet(encryptParamSet, encryptParams, sizeof(encryptParams) / sizeof(struct HksParam)); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("constuct encrypt param set failed, ret:%{public}d", ret); } return ret; } int32_t HuksAesAdapter::CreateDecryptParamSet(struct HksParamSet **decryptParamSet, struct HksBlob *decryptNonce, struct HksBlob *decryptAead) { struct HksParam decryptParams[] = { { .tag = HKS_TAG_ALGORITHM, .uint32Param = HKS_ALG_AES }, { .tag = HKS_TAG_PURPOSE, .uint32Param = HKS_KEY_PURPOSE_DECRYPT }, { .tag = HKS_TAG_KEY_SIZE, .uint32Param = HKS_AES_KEY_SIZE_128 }, { .tag = HKS_TAG_PADDING, .uint32Param = HKS_PADDING_NONE }, { .tag = HKS_TAG_BLOCK_MODE, .uint32Param = HKS_MODE_GCM }, { .tag = HKS_TAG_DIGEST, .uint32Param = HKS_DIGEST_NONE }, { .tag = HKS_TAG_ASSOCIATED_DATA, .blob = { .size = static_cast(strlen(g_aadValue)), .data = reinterpret_cast(g_aadValue) } }, { .tag = HKS_TAG_NONCE, .blob = { .size = decryptNonce->size, .data = decryptNonce->data } }, { .tag = HKS_TAG_AE_TAG, .blob = { .size = decryptAead->size, .data = decryptAead->data } }, { .tag = HKS_TAG_AUTH_STORAGE_LEVEL, .uint32Param = HKS_AUTH_STORAGE_LEVEL_DE } }; int32_t ret = ConstructParamSet(decryptParamSet, decryptParams, sizeof(decryptParams) / sizeof(struct HksParam)); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("constuct decrypt param set failed, ret:%{public}d", ret); } return ret; } int32_t HuksAesAdapter::Encrypt(std::unique_ptr &inBuffer, std::unique_ptr &outBuffer) { CHECK_CONDITION_RETURN_RET(((inBuffer == nullptr) || (inBuffer->GetSize() == 0)), HKS_ERROR_INVALID_ARGUMENT, "invalid arguments"); struct HksBlob keyAlias = { static_cast(strlen(g_aliasName)), reinterpret_cast(g_aliasName) }; bool isExist = false; int32_t ret = IsKeyExist(&keyAlias, isExist); CHECK_CONDITION_RETURN_RET((ret != HKS_SUCCESS), ret, "key exist failed"); if (!isExist) { ret = GenerateKey(&keyAlias); CHECK_CONDITION_RETURN_RET((ret != HKS_SUCCESS), ret, "generate key failed"); } struct HksParamSet *encryptParamSet = nullptr; uint8_t nonceValue[NONCE_SIZE] = { 0 }; struct HksBlob encryptNonce = { NONCE_SIZE, nonceValue}; ret = CreateEncryptParamSet(&encryptParamSet, &encryptNonce); CHECK_CONDITION_RETURN_RET((ret != HKS_SUCCESS), ret, "create encrypt param set failed"); ON_SCOPE_EXIT { HksFreeParamSet(&encryptParamSet); }; uint8_t handle[sizeof(uint64_t)] = {0}; struct HksBlob handleEncrypt = { sizeof(uint64_t), handle }; ret = HksInit(&keyAlias, encryptParamSet, &handleEncrypt, nullptr); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("huks init failed, ret:%{public}d", ret); return ret; } struct HksBlob inData = { inBuffer->GetSize() * sizeof(uint8_t), inBuffer->GetData() }; auto encryptData = std::make_unique(inBuffer->GetSize() * sizeof(uint8_t) + NONCE_SIZE + AEAD_SIZE); CHECK_CONDITION_RETURN_RET((encryptData == nullptr), HKS_ERROR_MALLOC_FAIL, "encryptData is nullptr"); struct HksBlob outData = { inBuffer->GetSize() * sizeof(uint8_t) + AEAD_SIZE, encryptData.get() + NONCE_SIZE }; ret = UpdateAndFinish(&handleEncrypt, encryptParamSet, &inData, &outData); CHECK_CONDITION_RETURN_RET((ret != HKS_SUCCESS), ret, "update and finish failed"); (void)memcpy_s(encryptData.get(), NONCE_SIZE, encryptNonce.data, encryptNonce.size); outBuffer = CreateArrayBuffer(outData.size + NONCE_SIZE, encryptData.get()); if (outBuffer == nullptr) { INTELL_VOICE_LOG_ERROR("allocate out buffer failed, size:%{public}u", outData.size); return HKS_ERROR_MALLOC_FAIL; } return HKS_SUCCESS; } int32_t HuksAesAdapter::Decrypt(std::unique_ptr &inBuffer, std::unique_ptr &outBuffer) { if ((inBuffer == nullptr) || (inBuffer->GetSize() <= (NONCE_SIZE + AEAD_SIZE))) { return HKS_ERROR_INVALID_ARGUMENT; } struct HksBlob keyAlias = { static_cast(strlen(g_aliasName)), reinterpret_cast(g_aliasName) }; bool isExist = false; int32_t ret = IsKeyExist(&keyAlias, isExist); CHECK_CONDITION_RETURN_RET((ret != HKS_SUCCESS), ret, "key exist failed"); CHECK_CONDITION_RETURN_RET((!isExist), HKS_FAILURE, "key is not exist"); struct HksParamSet *decryptParamSet = nullptr; struct HksBlob decryptNonce = { NONCE_SIZE, inBuffer->GetData() }; struct HksBlob decryptAead = { AEAD_SIZE, inBuffer->GetData() + inBuffer->GetSize() * sizeof(uint8_t) - AEAD_SIZE}; ret = CreateDecryptParamSet(&decryptParamSet, &decryptNonce, &decryptAead); CHECK_CONDITION_RETURN_RET((ret != HKS_SUCCESS), ret, "create decrypt param set failed"); ON_SCOPE_EXIT { HksFreeParamSet(&decryptParamSet); }; uint8_t handle[sizeof(uint64_t)] = { 0 }; struct HksBlob handleDecrypt = { sizeof(uint64_t), handle }; ret = HksInit(&keyAlias, decryptParamSet, &handleDecrypt, nullptr); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("huks init failed, ret:%{public}d", ret); return ret; } auto decryptData = std::make_unique(inBuffer->GetSize() * sizeof(uint8_t) - NONCE_SIZE - AEAD_SIZE); CHECK_CONDITION_RETURN_RET((decryptData == nullptr), HKS_ERROR_MALLOC_FAIL, "decryptData is nullptr"); struct HksBlob inData = { inBuffer->GetSize() * sizeof(uint8_t) - NONCE_SIZE - AEAD_SIZE, inBuffer->GetData() + NONCE_SIZE }; struct HksBlob outData = { inBuffer->GetSize() * sizeof(uint8_t) - NONCE_SIZE - AEAD_SIZE, decryptData.get() }; ret = UpdateAndFinish(&handleDecrypt, decryptParamSet, &inData, &outData); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("update and finish failed, size:%{public}u", outData.size); return ret; } outBuffer = CreateArrayBuffer(outData.size, outData.data); if (outBuffer == nullptr) { INTELL_VOICE_LOG_ERROR("allocate out buffer failed, size:%{public}u", outData.size); return HKS_ERROR_MALLOC_FAIL; } return HKS_SUCCESS; } int32_t HuksAesAdapter::IsKeyExist(struct HksBlob *keyAlias, bool &isExist) { struct HksParamSet *existParamSet = nullptr; int32_t ret = ConstructParamSet(&existParamSet, g_existParams, sizeof(g_existParams) / sizeof(struct HksParam)); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("constuct exist param set failed"); return ret; } if (HksKeyExist(keyAlias, existParamSet) == HKS_SUCCESS) { INTELL_VOICE_LOG_INFO("key is already exist"); isExist = true; } else { INTELL_VOICE_LOG_INFO("key is not exist"); isExist = false; } HksFreeParamSet(&existParamSet); return HKS_SUCCESS; } int32_t HuksAesAdapter::GenerateKey(struct HksBlob *keyAlias) { struct HksParamSet *genParamSet = nullptr; int32_t ret = ConstructParamSet(&genParamSet, g_genParams, sizeof(g_genParams) / sizeof(struct HksParam)); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("constuct gen param set failed"); return ret; } ret = HksGenerateKey(keyAlias, genParamSet, nullptr); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("generate key failed, ret:%{public}d", ret); } HksFreeParamSet(&genParamSet); return ret; } int32_t HuksAesAdapter::ConstructParamSet(struct HksParamSet **paramSet, const struct HksParam *params, uint32_t paramCount) { int32_t ret = HksInitParamSet(paramSet); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("HksInitParamSet failed, ret:%{public}d", ret); return ret; } ON_SCOPE_EXIT { HksFreeParamSet(paramSet); }; ret = HksAddParams(*paramSet, params, paramCount); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("HksAddParams failed, ret:%{public}d", ret); return ret; } ret = HksBuildParamSet(paramSet); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("HksBuildParamSet failed, ret:%{public}d", ret); return ret; } CANCEL_SCOPE_EXIT; return ret; } int32_t HuksAesAdapter::UpdateAndFinish(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, struct HksBlob *outData) { struct HksBlob inDataSeg = { MAX_UPDATE_SIZE, inData->data }; struct HksBlob outDataSeg = { MAX_OUTDATA_SIZE, nullptr }; uint32_t inUpdateSize = 0; uint8_t *outDataAddr = outData->data; uint32_t outUpdateSize = 0; int32_t ret = HKS_SUCCESS; while (inUpdateSize < inData->size) { if (inUpdateSize + MAX_UPDATE_SIZE >= inData->size) { inDataSeg.size = inData->size - inUpdateSize; break; } std::unique_ptr tmpUpdateBuff= CreateArrayBuffer(outDataSeg.size); CHECK_CONDITION_RETURN_RET((tmpUpdateBuff == nullptr), HKS_FAILURE, "tmpUpdateBuff is nullptr"); outDataSeg.data = tmpUpdateBuff->GetData(); ret = HksUpdate(handle, paramSet, &inDataSeg, &outDataSeg); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("Hks update failed, ret:%{public}d", ret); return HKS_FAILURE; } if (outUpdateSize + outDataSeg.size > outData->size) { INTELL_VOICE_LOG_ERROR("Hks update size failed, outUpdateSize:%{public}u", outUpdateSize); return HKS_FAILURE; } (void)memcpy_s(outDataAddr, outData->size - outUpdateSize, outDataSeg.data, outDataSeg.size); outDataAddr += outDataSeg.size; outUpdateSize += outDataSeg.size; tmpUpdateBuff = nullptr; inUpdateSize += MAX_UPDATE_SIZE; inDataSeg.data = inData->data + inUpdateSize; } std::unique_ptr tmpFinishBuff= CreateArrayBuffer(inDataSeg.size + AEAD_SIZE); CHECK_CONDITION_RETURN_RET((tmpFinishBuff == nullptr), HKS_FAILURE, "tmpFinishBuff is nullptr"); struct HksBlob outDataFinish = { tmpFinishBuff->GetSize() * sizeof(uint8_t), tmpFinishBuff->GetData() }; ret = HksFinish(handle, paramSet, &inDataSeg, &outDataFinish); if (ret != HKS_SUCCESS) { INTELL_VOICE_LOG_ERROR("Hks finish failed, ret:%{public}d", ret); return HKS_FAILURE; } if (outUpdateSize + outDataFinish.size > outData->size) { INTELL_VOICE_LOG_ERROR("%{public}u, %{public}u, %{public}u", outUpdateSize, outDataFinish.size, outData->size); return HKS_FAILURE; } (void)memcpy_s(outDataAddr, outData->size - outUpdateSize, outDataFinish.data, outDataFinish.size); outData->size = outUpdateSize + outDataFinish.size; return HKS_SUCCESS; } } }