1# Importing a Key in Ciphertext (C/C++) 2 3<!--Kit: Universal Keystore Kit--> 4<!--Subsystem: Security--> 5<!--Owner: @wutiantian-gitee--> 6<!--Designer: @HighLowWorld--> 7<!--Tester: @wxy1234564846--> 8<!--Adviser: @zengyawen--> 9 10This topic walks you through on how to import an ECDH key pair. However, the example does not cover the operations such as [key generation](huks-key-generation-overview.md) and [key agreement](huks-key-agreement-overview.md) of the service side. 11 12For details about the scenarios and supported algorithm specifications, see [Supported Algorithms](huks-key-import-overview.md#supported-algorithms). 13 14## Add the dynamic library in the CMake script. 15```txt 16target_link_libraries(entry PUBLIC libhuks_ndk.z.so) 17``` 18 19## How to Develop 20 211. Convert the key to be imported from device A (device from which the key is imported) to [HUKS key material format](huks-concepts.md#key material format) **To_Import_Key**. (This step applies only to asymmetric key pairs. If the key to be imported is a symmetric key, skip over this step.) 22 232. Generate an asymmetric key pair **Wrapping_Key** (public key **Wrapping_Pk** and private key **Wrapping_Sk**) with the purpose of **HUKS_KEY_PURPOSE_UNWRAP** for device B (device to which the key is imported), and export the public key **Wrapping_Pk** of **Wrapping_Key** and save it. The asymmetric key pair **Wrapping_Key** is used for key agreement in the encrypted import process. 24 253. Use the same algorithm to generate an asymmetric key pair **Caller_Key** (public key **Caller_Pk** and private key **Caller_Sk**) with the purpose of **HUKS_KEY_PURPOSE_UNWRAP** for device A, and export the public key **Caller_Pk** of **Caller_Key** and save it. The asymmetric key pair **Caller_Key** is used for key agreement in the encrypted import process. 26 274. Generate a symmetric key **Caller_Kek** for device A. This key is used to encrypt **To_Import_Key**. 28 295. Perform key agreement with the private key **Caller_Sk** in **Caller_Key** of device A and the public key **Wrapping_Pk** in **Wrapping_Key** of device B to yield a **Shared_Key**. 30 316. Use **Caller_Kek** to encrypt **To_Import_Key** of device A and generate **To_Import_Key_Enc**. 32 337. Use **Shared_Key** to encrypt **Caller_Kek** of device A and generate **Caller_Kek_Enc**. 34 358. Encapsulate the key material **Caller_Pk**, **Caller_Kek_Enc**, and **To_Import_Key_Enc** of device A, and sends it to device B. For details about the format of the key material to be imported, see [Key Material Format for Encrypted Import](huks-key-import-overview.md#key-material-format-for-encrypted-import). 36 379. Import the encrypted key material to device B. 38 3910. Delete the intermediate keys (keys used for encrypting the key to import) from devices A and B. 40 41```c++ 42#include "huks/native_huks_api.h" 43#include "huks/native_huks_param.h" 44#include "napi/native_api.h" 45#include <algorithm> 46OH_Huks_Result InitParamSet(struct OH_Huks_ParamSet **paramSet, const struct OH_Huks_Param *params, 47 uint32_t paramCount) { 48 OH_Huks_Result ret = OH_Huks_InitParamSet(paramSet); 49 if (ret.errorCode != OH_HUKS_SUCCESS) { 50 return ret; 51 } 52 ret = OH_Huks_AddParams(*paramSet, params, paramCount); 53 if (ret.errorCode != OH_HUKS_SUCCESS) { 54 OH_Huks_FreeParamSet(paramSet); 55 return ret; 56 } 57 ret = OH_Huks_BuildParamSet(paramSet); 58 if (ret.errorCode != OH_HUKS_SUCCESS) { 59 OH_Huks_FreeParamSet(paramSet); 60 return ret; 61 } 62 return ret; 63} 64struct HksImportWrappedKeyTestParams { 65 // server key, for real. 66 struct OH_Huks_Blob *wrappingKeyAlias; 67 struct OH_Huks_ParamSet *genWrappingKeyParamSet; 68 uint32_t publicKeySize; 69 struct OH_Huks_Blob *callerKeyAlias; 70 struct OH_Huks_ParamSet *genCallerKeyParamSet; 71 struct OH_Huks_Blob *callerKekAlias; 72 struct OH_Huks_Blob *callerKek; 73 struct OH_Huks_ParamSet *importCallerKekParamSet; 74 struct OH_Huks_Blob *callerAgreeKeyAlias; 75 struct OH_Huks_ParamSet *agreeParamSet; 76 struct OH_Huks_ParamSet *importWrappedKeyParamSet; 77 struct OH_Huks_Blob *importedKeyAlias; 78 struct OH_Huks_Blob *importedPlainKey; 79 uint32_t keyMaterialLen; 80}; 81static const uint32_t IV_SIZE = 16; 82static uint8_t IV[IV_SIZE] = "babababababab"; // Test data only. The value must be different each time. 83static const uint32_t WRAPPED_KEY_IV_SIZE = 16; 84static uint8_t WRAPPED_KEY_IV[IV_SIZE] = "bababababababab"; // Test data only. The value must be different each time. 85static const uint32_t AAD_SIZE = 16; 86static uint8_t AAD[AAD_SIZE] = "abababababababa"; // Test data only. The value must be different each time. 87static const uint32_t NONCE_SIZE = 12; 88static uint8_t NONCE[NONCE_SIZE] = "hahahahahah"; // Test data only. The value must be different each time. 89static const uint32_t AEAD_TAG_SIZE = 16; 90static const uint32_t X25519_256_SIZE = 256; 91static struct OH_Huks_Blob g_wrappingKeyAliasAes256 = {.size = (uint32_t)strlen("test_wrappingKey_x25519_aes256"), 92 .data = (uint8_t *)"test_wrappingKey_x25519_aes256"}; 93static struct OH_Huks_Blob g_callerKeyAliasAes256 = {.size = (uint32_t)strlen("test_caller_key_x25519_aes256"), 94 .data = (uint8_t *)"test_caller_key_x25519_aes256"}; 95static struct OH_Huks_Blob g_callerKekAliasAes256 = {.size = (uint32_t)strlen("test_caller_kek_x25519_aes256"), 96 .data = (uint8_t *)"test_caller_kek_x25519_aes256"}; 97static struct OH_Huks_Blob g_callerAes256Kek = {.size = (uint32_t)strlen("This is kek to encrypt plain key"), 98 .data = (uint8_t *)"This is kek to encrypt plain key"}; 99static struct OH_Huks_Blob g_callerAgreeKeyAliasAes256 = {.size = 100 (uint32_t)strlen("test_caller_agree_key_x25519_aes256"), 101 .data = (uint8_t *)"test_caller_agree_key_x25519_aes256"}; 102static struct OH_Huks_Blob g_importedKeyAliasAes256 = {.size = (uint32_t)strlen("test_import_key_x25519_aes256"), 103 .data = (uint8_t *)"test_import_key_x25519_aes256"}; 104static struct OH_Huks_Blob g_importedAes256PlainKey = {.size = (uint32_t)strlen("This is plain key to be imported"), 105 .data = (uint8_t *)"This is plain key to be imported"}; 106static struct OH_Huks_Param g_importWrappedAes256Params[] = { 107 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES}, 108 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_ENCRYPT | OH_HUKS_KEY_PURPOSE_DECRYPT}, 109 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256}, 110 {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE}, 111 {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_GCM}, 112 {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE}, 113 {.tag = OH_HUKS_TAG_UNWRAP_ALGORITHM_SUITE, .uint32Param = OH_HUKS_UNWRAP_SUITE_X25519_AES_256_GCM_NOPADDING}, 114 {.tag = OH_HUKS_TAG_ASSOCIATED_DATA, 115 .blob = {.size = AAD_SIZE, .data = (uint8_t *)AAD}}, // Test data only. The value varies with the caller information. 116 {.tag = OH_HUKS_TAG_NONCE, 117 .blob = {.size = NONCE_SIZE, .data = (uint8_t *)NONCE}}}; // Test data only. The value must be different each time. 118static const uint32_t g_x25519PubKeySize = 32; 119static struct OH_Huks_Param g_genWrappingKeyParams[] = { 120 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_X25519}, 121 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_UNWRAP}, 122 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_CURVE25519_KEY_SIZE_256}}; 123static struct OH_Huks_Param g_genCallerX25519Params[] = { 124 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_X25519}, 125 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE}, 126 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_CURVE25519_KEY_SIZE_256}}; 127static struct OH_Huks_Param g_importParamsCallerKek[] = { 128 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES}, 129 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_ENCRYPT}, 130 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256}, 131 {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE}, 132 {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_GCM}, 133 {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE}, 134 {.tag = OH_HUKS_TAG_IV, 135 .blob = {.size = WRAPPED_KEY_IV_SIZE, 136 .data = (uint8_t *)WRAPPED_KEY_IV}}}; // Test data only. The value must be different each time. 137static struct OH_Huks_Param g_callerAgreeParams[] = { 138 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_X25519}, 139 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_AGREE}, 140 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_CURVE25519_KEY_SIZE_256}}; 141static struct OH_Huks_Param g_aesKekEncryptParams[] = { 142 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES}, 143 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_ENCRYPT}, 144 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256}, 145 {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE}, 146 {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_GCM}, 147 {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE}, 148 {.tag = OH_HUKS_TAG_ASSOCIATED_DATA, 149 .blob = {.size = AAD_SIZE, .data = (uint8_t *)AAD}}, // Test data only. The value varies with the caller information. 150 {.tag = OH_HUKS_TAG_NONCE, 151 .blob = {.size = NONCE_SIZE, .data = (uint8_t *)NONCE}}}; // Test data only. The value must be different each time. 152static struct OH_Huks_Param g_importAgreeKeyParams[] = { 153 {.tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_AES}, 154 {.tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_ENCRYPT}, 155 {.tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_AES_KEY_SIZE_256}, 156 {.tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_NONE}, 157 {.tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_GCM}, 158 {.tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_NONE}, 159 {.tag = OH_HUKS_TAG_IV, 160 .blob = {.size = IV_SIZE, .data = (uint8_t *)IV}}}; // Test data only. The value must be different each time. 161OH_Huks_Result HuksAgreeKey(const struct OH_Huks_ParamSet *paramSet, const struct OH_Huks_Blob *keyAlias, 162 const struct OH_Huks_Blob *peerPublicKey, struct OH_Huks_Blob *agreedKey) { 163 uint8_t temp[10] = {0}; 164 struct OH_Huks_Blob inData = {sizeof(temp), temp}; 165 uint8_t handleU[sizeof(uint64_t)] = {0}; 166 struct OH_Huks_Blob handle = {sizeof(uint64_t), handleU}; 167 OH_Huks_Result ret = OH_Huks_InitSession(keyAlias, paramSet, &handle, nullptr); 168 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 169 return ret; 170 } 171 uint8_t outDataU[1024] = {0}; 172 struct OH_Huks_Blob outDataUpdate = {1024, outDataU}; 173 ret = OH_Huks_UpdateSession(&handle, paramSet, peerPublicKey, &outDataUpdate); 174 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 175 return ret; 176 } 177 ret = OH_Huks_FinishSession(&handle, paramSet, &inData, agreedKey); 178 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 179 return ret; 180 } 181 return ret; 182} 183OH_Huks_Result MallocAndCheckBlobData(struct OH_Huks_Blob *blob, const uint32_t blobSize) { 184 struct OH_Huks_Result ret; 185 ret.errorCode = OH_HUKS_SUCCESS; 186 blob->data = (uint8_t *)malloc(blobSize); 187 if (blob->data == NULL) { 188 ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR; 189 } 190 return ret; 191} 192static const uint32_t TIMES = 4; 193static const uint32_t MAX_UPDATE_SIZE = 64; 194static const uint32_t MAX_OUTDATA_SIZE = MAX_UPDATE_SIZE * TIMES; 195#define HUKS_FREE_BLOB(blob) \ 196 do { \ 197 if ((blob).data != nullptr) { \ 198 free((blob).data); \ 199 (blob).data = nullptr; \ 200 } \ 201 (blob).size = 0; \ 202 } while (0) 203#define OH_HUKS_KEY_BYTES(keySize) (((keySize) + 7) / 8) 204static OH_Huks_Result HksEncryptLoopUpdate(const struct OH_Huks_Blob *handle, const struct OH_Huks_ParamSet *paramSet, 205 const struct OH_Huks_Blob *inData, struct OH_Huks_Blob *outData) { 206 struct OH_Huks_Result ret; 207 ret.errorCode = OH_HUKS_SUCCESS; 208 struct OH_Huks_Blob inDataSeg = *inData; 209 uint8_t *lastPtr = inData->data + inData->size - 1; 210 struct OH_Huks_Blob outDataSeg = {MAX_OUTDATA_SIZE, NULL}; 211 uint8_t *cur = outData->data; 212 outData->size = 0; 213 inDataSeg.size = MAX_UPDATE_SIZE; 214 bool isFinished = false; 215 while (inDataSeg.data <= lastPtr) { 216 if (inDataSeg.data + MAX_UPDATE_SIZE <= lastPtr) { 217 outDataSeg.size = MAX_OUTDATA_SIZE; 218 } else { 219 isFinished = true; 220 inDataSeg.size = lastPtr - inDataSeg.data + 1; 221 break; 222 } 223 if (MallocAndCheckBlobData(&outDataSeg, outDataSeg.size).errorCode != (int32_t)OH_HUKS_SUCCESS) { 224 ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR; 225 return ret; 226 } 227 ret = OH_Huks_UpdateSession(handle, paramSet, &inDataSeg, &outDataSeg); 228 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 229 free(outDataSeg.data); 230 return ret; 231 } 232 std::copy(outDataSeg.data, outDataSeg.data + outDataSeg.size, cur); 233 cur += outDataSeg.size; 234 outData->size += outDataSeg.size; 235 free(outDataSeg.data); 236 if ((isFinished == false) && (inDataSeg.data + MAX_UPDATE_SIZE > lastPtr)) { 237 ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR; 238 return ret; 239 } 240 inDataSeg.data += MAX_UPDATE_SIZE; 241 } 242 struct OH_Huks_Blob outDataFinish = {inDataSeg.size * TIMES, NULL}; 243 if (MallocAndCheckBlobData(&outDataFinish, outDataFinish.size).errorCode != (int32_t)OH_HUKS_SUCCESS) { 244 ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR; 245 return ret; 246 } 247 ret = OH_Huks_FinishSession(handle, paramSet, &inDataSeg, &outDataFinish); 248 if (ret.errorCode != OH_HUKS_SUCCESS) { 249 free(outDataFinish.data); 250 return ret; 251 } 252 std::copy(outDataFinish.data, outDataFinish.data + outDataFinish.size, cur); 253 outData->size += outDataFinish.size; 254 free(outDataFinish.data); 255 return ret; 256} 257OH_Huks_Result HuksEncrypt(const struct OH_Huks_Blob *key, const struct OH_Huks_ParamSet *paramSet, 258 const struct OH_Huks_Blob *plainText, struct OH_Huks_Blob *cipherText) { 259 uint8_t handle[sizeof(uint64_t)] = {0}; 260 struct OH_Huks_Blob handleBlob = {sizeof(uint64_t), handle}; 261 OH_Huks_Result ret = OH_Huks_InitSession(key, paramSet, &handleBlob, nullptr); 262 if (ret.errorCode != OH_HUKS_SUCCESS) { 263 return ret; 264 } 265 ret = HksEncryptLoopUpdate(&handleBlob, paramSet, plainText, cipherText); 266 return ret; 267} 268static OH_Huks_Result BuildWrappedKeyData(struct OH_Huks_Blob **blobArray, uint32_t size, 269 struct OH_Huks_Blob *outData) { 270 uint32_t totalLength = size * sizeof(uint32_t); 271 struct OH_Huks_Result ret; 272 ret.errorCode = OH_HUKS_SUCCESS; 273 /* Data size. */ 274 for (uint32_t i = 0; i < size; ++i) { 275 totalLength += blobArray[i]->size; 276 } 277 struct OH_Huks_Blob outBlob = {0, nullptr}; 278 outBlob.size = totalLength; 279 ret = MallocAndCheckBlobData(&outBlob, outBlob.size); 280 if (ret.errorCode != OH_HUKS_SUCCESS) { 281 return ret; 282 } 283 uint32_t offset = 0; 284 /* Copy data. */ 285 for (uint32_t i = 0; i < size; ++i) { 286 if (totalLength - offset >= sizeof(blobArray[i]->size)) { 287 std::copy(reinterpret_cast<uint8_t *>(&blobArray[i]->size), 288 reinterpret_cast<uint8_t *>(&blobArray[i]->size) + sizeof(blobArray[i]->size), 289 outBlob.data + offset); 290 } else { 291 ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR; 292 return ret; 293 } 294 offset += sizeof(blobArray[i]->size); 295 if (totalLength - offset >= blobArray[i]->size) { 296 std::copy(blobArray[i]->data, blobArray[i]->data + blobArray[i]->size, outBlob.data + offset); 297 } else { 298 ret.errorCode = OH_HUKS_ERR_CODE_INTERNAL_ERROR; 299 return ret; 300 } 301 offset += blobArray[i]->size; 302 } 303 outData->size = outBlob.size; 304 outData->data = outBlob.data; 305 return ret; 306} 307static OH_Huks_Result CheckParamsValid(const struct HksImportWrappedKeyTestParams *params) { 308 struct OH_Huks_Result ret; 309 ret.errorCode = OH_HUKS_SUCCESS; 310 if (params == nullptr) { 311 ret.errorCode = OH_HUKS_ERR_CODE_ILLEGAL_ARGUMENT; 312 return ret; 313 } 314 if (params->wrappingKeyAlias == nullptr || params->genWrappingKeyParamSet == nullptr || 315 params->callerKeyAlias == nullptr || params->genCallerKeyParamSet == nullptr || 316 params->callerKekAlias == nullptr || params->callerKek == nullptr || 317 params->importCallerKekParamSet == nullptr || params->callerAgreeKeyAlias == nullptr || 318 params->agreeParamSet == nullptr || params->importWrappedKeyParamSet == nullptr || 319 params->importedKeyAlias == nullptr || params->importedPlainKey == nullptr) { 320 ret.errorCode = OH_HUKS_ERR_CODE_ILLEGAL_ARGUMENT; 321 return ret; 322 } 323 return ret; 324} 325static OH_Huks_Result GenerateAndExportHuksPublicKey(const struct HksImportWrappedKeyTestParams *params, 326 struct OH_Huks_Blob *huksPublicKey) { 327 OH_Huks_Result ret = OH_Huks_GenerateKeyItem(params->wrappingKeyAlias, params->genWrappingKeyParamSet, nullptr); 328 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 329 return ret; 330 } 331 huksPublicKey->size = params->publicKeySize; 332 ret = MallocAndCheckBlobData(huksPublicKey, huksPublicKey->size); 333 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 334 return ret; 335 } 336 ret = OH_Huks_ExportPublicKeyItem(params->wrappingKeyAlias, nullptr, huksPublicKey); 337 return ret; 338} 339static OH_Huks_Result GenerateAndExportCallerPublicKey(const struct HksImportWrappedKeyTestParams *params, 340 struct OH_Huks_Blob *callerSelfPublicKey) { 341 OH_Huks_Result ret = OH_Huks_GenerateKeyItem(params->callerKeyAlias, params->genCallerKeyParamSet, nullptr); 342 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 343 return ret; 344 } 345 callerSelfPublicKey->size = params->publicKeySize; 346 ret = MallocAndCheckBlobData(callerSelfPublicKey, callerSelfPublicKey->size); 347 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 348 return ret; 349 } 350 ret = OH_Huks_ExportPublicKeyItem(params->callerKeyAlias, params->genWrappingKeyParamSet, callerSelfPublicKey); 351 return ret; 352} 353static OH_Huks_Result ImportKekAndAgreeSharedSecret(const struct HksImportWrappedKeyTestParams *params, 354 const struct OH_Huks_Blob *huksPublicKey, 355 struct OH_Huks_Blob *outSharedKey) { 356 OH_Huks_Result ret = 357 OH_Huks_ImportKeyItem(params->callerKekAlias, params->importCallerKekParamSet, params->callerKek); 358 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 359 return ret; 360 } 361 ret = MallocAndCheckBlobData(outSharedKey, outSharedKey->size); 362 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 363 return ret; 364 } 365 ret = HuksAgreeKey(params->agreeParamSet, params->callerKeyAlias, huksPublicKey, outSharedKey); 366 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 367 return ret; 368 } 369 struct OH_Huks_ParamSet *importAgreeKeyParams = nullptr; 370 ret = InitParamSet(&importAgreeKeyParams, g_importAgreeKeyParams, 371 sizeof(g_importAgreeKeyParams) / sizeof(OH_Huks_Param)); 372 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 373 return ret; 374 } 375 ret = OH_Huks_ImportKeyItem(params->callerAgreeKeyAlias, importAgreeKeyParams, outSharedKey); 376 OH_Huks_FreeParamSet(&importAgreeKeyParams); 377 return ret; 378} 379static OH_Huks_Result EncryptImportedPlainKeyAndKek(const struct HksImportWrappedKeyTestParams *params, 380 struct OH_Huks_Blob *plainCipherText, 381 struct OH_Huks_Blob *kekCipherText) { 382 struct OH_Huks_ParamSet *encryptParamSet = nullptr; 383 OH_Huks_Result ret = 384 InitParamSet(&encryptParamSet, g_aesKekEncryptParams, sizeof(g_aesKekEncryptParams) / sizeof(OH_Huks_Param)); 385 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 386 return ret; 387 } 388 ret = HuksEncrypt(params->callerKekAlias, encryptParamSet, params->importedPlainKey, plainCipherText); 389 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 390 return ret; 391 } 392 ret = HuksEncrypt(params->callerAgreeKeyAlias, encryptParamSet, params->callerKek, kekCipherText); 393 OH_Huks_FreeParamSet(&encryptParamSet); 394 return ret; 395} 396static OH_Huks_Result ImportWrappedKey(const struct HksImportWrappedKeyTestParams *params, 397 struct OH_Huks_Blob *plainCipher, struct OH_Huks_Blob *kekCipherText, 398 struct OH_Huks_Blob *peerPublicKey, struct OH_Huks_Blob *wrappedKeyData) { 399 struct OH_Huks_Blob commonAad = {.size = AAD_SIZE, .data = reinterpret_cast<uint8_t *>(AAD)}; 400 struct OH_Huks_Blob commonNonce = {.size = NONCE_SIZE, .data = reinterpret_cast<uint8_t *>(NONCE)}; 401 struct OH_Huks_Blob keyMaterialLen = {.size = sizeof(uint32_t), .data = (uint8_t *)¶ms->keyMaterialLen}; 402 /* Copy the AEAD tag from the ciphertext and reduce its size. */ 403 const uint32_t tagSize = AEAD_TAG_SIZE; 404 uint8_t kekTagBuf[tagSize] = {0}; 405 struct OH_Huks_Blob kekTag = {.size = tagSize, .data = kekTagBuf}; 406 std::copy(plainCipher->data + (plainCipher->size - tagSize), 407 plainCipher->data + (plainCipher->size - tagSize) + tagSize, kekTag.data); 408 plainCipher->size -= tagSize; 409 /* Copy the AEAD tag from kekCipherText and reduce the tag size. */ 410 uint8_t agreeKeyTagBuf[tagSize] = {0}; 411 struct OH_Huks_Blob agreeKeyTag = {.size = tagSize, .data = agreeKeyTagBuf}; 412 std::copy(kekCipherText->data + (kekCipherText->size - tagSize), 413 kekCipherText->data + (kekCipherText->size - tagSize) + tagSize, agreeKeyTagBuf); 414 kekCipherText->size -= tagSize; 415 struct OH_Huks_Blob *blobArray[] = {peerPublicKey, &commonAad, &commonNonce, &agreeKeyTag, kekCipherText, 416 &commonAad, &commonNonce, &kekTag, &keyMaterialLen, plainCipher}; 417 OH_Huks_Result ret = BuildWrappedKeyData(blobArray, OH_HUKS_IMPORT_WRAPPED_KEY_TOTAL_BLOBS, wrappedKeyData); 418 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 419 return ret; 420 } 421 struct OH_Huks_Param *purpose = nullptr; 422 ret = OH_Huks_GetParam(params->importWrappedKeyParamSet, OH_HUKS_TAG_PURPOSE, &purpose); 423 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 424 return ret; 425 } 426 ret = OH_Huks_ImportWrappedKeyItem(params->importedKeyAlias, params->wrappingKeyAlias, 427 params->importWrappedKeyParamSet, wrappedKeyData); 428 return ret; 429} 430OH_Huks_Result HksImportWrappedKeyTestCommonCase(const struct HksImportWrappedKeyTestParams *params) { 431 OH_Huks_Result ret = CheckParamsValid(params); 432 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 433 return ret; 434 } 435 struct OH_Huks_Blob huksPublicKey = {0, nullptr}; 436 struct OH_Huks_Blob callerSelfPublicKey = {0, nullptr}; 437 struct OH_Huks_Blob outSharedKey = {.size = OH_HUKS_KEY_BYTES(OH_HUKS_AES_KEY_SIZE_256), .data = nullptr}; 438 struct OH_Huks_Blob wrappedKeyData = {0, nullptr}; 439 uint8_t plainKeyCipherBuffer[OH_HUKS_MAX_KEY_SIZE] = {0}; 440 struct OH_Huks_Blob plainCipherText = {OH_HUKS_MAX_KEY_SIZE, plainKeyCipherBuffer}; 441 uint8_t kekCipherTextBuffer[OH_HUKS_MAX_KEY_SIZE] = {0}; 442 struct OH_Huks_Blob kekCipherText = {OH_HUKS_MAX_KEY_SIZE, kekCipherTextBuffer}; 443 /* Simulate the encrypted key import scenario. Import a key from device A (remote device) to device B (local device). */ 444 do { 445 /** 446 * 1. If the key to be imported from device A is an asymmetric key pair, convert it into the HUKS key material format **To_Import_Key**. Skip over this step if the key is a symmetric key. 447 * This example uses a 256-bit AES key (symmetric key) as an example. 448 */ 449 /* 2. Generate an asymmetric key pair Wrapping_Key (public key Wrapping_Pk and private key Wrapping_Sk) with the purpose of HUKS_KEY_PURPOSE_UNWRAP for device B, export the public key Wrapping_Pk of Wrapping_Key, and save it to huksPubKey. 450 */ 451 ret = GenerateAndExportHuksPublicKey(params, &huksPublicKey); 452 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 453 break; 454 } 455 /* 3. Use the same algorithm to generate an asymmetric key pair Caller_Key (public key Caller_Pk and private key Caller_Sk) with the purpose of HUKS_KEY_PURPOSE_UNWRAP for device A, export the public key Caller_Pk of Caller_Key, save it to callerSelfPublicKey. 456 */ 457 ret = GenerateAndExportCallerPublicKey(params, &callerSelfPublicKey); 458 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 459 break; 460 } 461 /** 462 4. Generate a symmetric key Caller_Kek for device A. This key is used to encrypt To_Import_Key. 463 * 5. Perform key agreement with the private key **Caller_Sk** in **Caller_Key** of device A and the public key **Wrapping_Pk** in **Wrapping_Key** of device B to yield a **Shared_Key**. 464 */ 465 ret = ImportKekAndAgreeSharedSecret(params, &huksPublicKey, &outSharedKey); 466 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 467 break; 468 } 469 /** 470 * 6. Use Caller_Kek to encrypt To_Import_Key of device A and generate To_Import_Key_Enc. 471 * 7. Use Shared_Key to encrypt Caller_Kek of device A and generate Caller_Kek_Enc. 472 */ 473 ret = EncryptImportedPlainKeyAndKek(params, &plainCipherText, &kekCipherText); 474 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 475 break; 476 } 477 /* 8. Encapsulate the key material Caller_Pk, To_Import_Key_Enc, and Caller_Kek_Enc of device A, and sends it to device B. 478 * In this example, Caller_Pk is placed in callerSelfPublicKey, To_Import_Key_Enc in PlainKeyEncData, and Caller_Kek_Enc in KekEncData. 479 * 9. Import the encapsulated key material to device B. 480 */ 481 ret = ImportWrappedKey(params, &plainCipherText, &kekCipherText, &callerSelfPublicKey, &wrappedKeyData); 482 } while (0); 483 /* 10. Delete the intermediate keys (keys used for encrypting the key to import) from devices A and B. */ 484 HUKS_FREE_BLOB(huksPublicKey); 485 HUKS_FREE_BLOB(callerSelfPublicKey); 486 HUKS_FREE_BLOB(outSharedKey); 487 HUKS_FREE_BLOB(wrappedKeyData); 488 return ret; 489} 490void HksClearKeysForWrappedKeyTest(const struct HksImportWrappedKeyTestParams *params) { 491 OH_Huks_Result ret = CheckParamsValid(params); 492 if (ret.errorCode != (int32_t)OH_HUKS_SUCCESS) { 493 return; 494 } 495 (void)OH_Huks_DeleteKeyItem(params->wrappingKeyAlias, nullptr); 496 (void)OH_Huks_DeleteKeyItem(params->callerKeyAlias, nullptr); 497 (void)OH_Huks_DeleteKeyItem(params->callerKekAlias, nullptr); 498 (void)OH_Huks_DeleteKeyItem(params->callerAgreeKeyAlias, nullptr); 499 (void)OH_Huks_DeleteKeyItem(params->importedKeyAlias, nullptr); 500} 501static OH_Huks_Result InitCommonTestParamsAndDoImport(struct HksImportWrappedKeyTestParams *importWrappedKeyTestParams, 502 const struct OH_Huks_Param *importedKeyParamSetArray, 503 uint32_t arraySize) { 504 struct OH_Huks_ParamSet *genX25519KeyParamSet = nullptr; 505 struct OH_Huks_ParamSet *genCallerKeyParamSet = nullptr; 506 struct OH_Huks_ParamSet *callerImportParamsKek = nullptr; 507 struct OH_Huks_ParamSet *agreeParamSet = nullptr; 508 struct OH_Huks_ParamSet *importPlainKeyParams = nullptr; 509 OH_Huks_Result ret; 510 do { 511 ret = InitParamSet(&genX25519KeyParamSet, g_genWrappingKeyParams, 512 sizeof(g_genWrappingKeyParams) / sizeof(OH_Huks_Param)); 513 if (ret.errorCode != OH_HUKS_SUCCESS) { 514 break; 515 } 516 importWrappedKeyTestParams->genWrappingKeyParamSet = genX25519KeyParamSet; 517 importWrappedKeyTestParams->publicKeySize = g_x25519PubKeySize; 518 ret = InitParamSet(&genCallerKeyParamSet, g_genCallerX25519Params, 519 sizeof(g_genCallerX25519Params) / sizeof(OH_Huks_Param)); 520 if (ret.errorCode != OH_HUKS_SUCCESS) { 521 break; 522 } 523 importWrappedKeyTestParams->genCallerKeyParamSet = genCallerKeyParamSet; 524 ret = InitParamSet(&callerImportParamsKek, g_importParamsCallerKek, 525 sizeof(g_importParamsCallerKek) / sizeof(OH_Huks_Param)); 526 if (ret.errorCode != OH_HUKS_SUCCESS) { 527 break; 528 } 529 importWrappedKeyTestParams->importCallerKekParamSet = callerImportParamsKek; 530 ret = InitParamSet(&agreeParamSet, g_callerAgreeParams, sizeof(g_callerAgreeParams) / sizeof(OH_Huks_Param)); 531 if (ret.errorCode != OH_HUKS_SUCCESS) { 532 break; 533 } 534 importWrappedKeyTestParams->agreeParamSet = agreeParamSet; 535 ret = InitParamSet(&importPlainKeyParams, importedKeyParamSetArray, arraySize); 536 if (ret.errorCode != OH_HUKS_SUCCESS) { 537 break; 538 } 539 importWrappedKeyTestParams->importWrappedKeyParamSet = importPlainKeyParams; 540 ret = HksImportWrappedKeyTestCommonCase(importWrappedKeyTestParams); 541 } while (0); 542 OH_Huks_FreeParamSet(&genX25519KeyParamSet); 543 OH_Huks_FreeParamSet(&genCallerKeyParamSet); 544 OH_Huks_FreeParamSet(&callerImportParamsKek); 545 OH_Huks_FreeParamSet(&agreeParamSet); 546 OH_Huks_FreeParamSet(&importPlainKeyParams); 547 return ret; 548} 549static napi_value ImportWrappedKey(napi_env env, napi_callback_info info) { 550 struct HksImportWrappedKeyTestParams importWrappedKeyTestParams001 = {0}; 551 importWrappedKeyTestParams001.wrappingKeyAlias = &g_wrappingKeyAliasAes256; 552 importWrappedKeyTestParams001.keyMaterialLen = g_importedAes256PlainKey.size; 553 importWrappedKeyTestParams001.callerKeyAlias = &g_callerKeyAliasAes256; 554 importWrappedKeyTestParams001.callerKekAlias = &g_callerKekAliasAes256; 555 importWrappedKeyTestParams001.callerKek = &g_callerAes256Kek; 556 importWrappedKeyTestParams001.callerAgreeKeyAlias = &g_callerAgreeKeyAliasAes256; 557 importWrappedKeyTestParams001.importedKeyAlias = &g_importedKeyAliasAes256; 558 importWrappedKeyTestParams001.importedPlainKey = &g_importedAes256PlainKey; 559 OH_Huks_Result ohResult = 560 InitCommonTestParamsAndDoImport(&importWrappedKeyTestParams001, g_importWrappedAes256Params, 561 sizeof(g_importWrappedAes256Params) / sizeof(struct OH_Huks_Param)); 562 HksClearKeysForWrappedKeyTest(&importWrappedKeyTestParams001); 563 napi_value ret; 564 napi_create_int32(env, ohResult.errorCode, &ret); 565 return ret; 566} 567``` 568 569 570## Verification 571 572Use [OH_Huks_IsKeyItemExist](../../reference/apis-universal-keystore-kit/capi-native-huks-api-h.md#oh_huks_iskeyitemexist) to check whether the key exists. If the key exists, the key is successfully imported. 573 574```c++ 575#include "huks/native_huks_api.h" 576#include "huks/native_huks_param.h" 577#include "napi/native_api.h" 578#include <string.h> 579static napi_value IsKeyExist(napi_env env, napi_callback_info info) 580{ 581 /* 1. Set the key alias. */ 582 struct OH_Huks_Blob keyAlias = { 583 (uint32_t)strlen("test_key"), 584 (uint8_t *)"test_key" 585 }; 586 587 /* 2. Call OH_Huks_IsKeyItemExist to check whether the key exists. */ 588 struct OH_Huks_Result ohResult = OH_Huks_IsKeyItemExist(&keyAlias, NULL); 589 if (ohResult.errorCode != OH_HUKS_SUCCESS) { 590 // Failed. 591 } else { 592 // Successful. 593 } 594 napi_value ret; 595 napi_create_int32(env, ohResult.errorCode, &ret); 596 return ret; 597} 598``` 599