• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *)&params->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