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