• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Importing a Key in Ciphertext (ArkTS)
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## How to Develop
15
161. 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.)
17
182. 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.
19
203. 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.
21
224. Generate a symmetric key **Caller_Kek** for device A. This key is used to encrypt **To_Import_Key**.
23
245. 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**.
25
266. Use **Caller_Kek** to encrypt **To_Import_Key** of device A and generate **To_Import_Key_Enc**.
27
287. Use **Shared_Key** to encrypt **Caller_Kek** of device A and generate **Caller_Kek_Enc**.
29
308. 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).
31
329. Import the encrypted key material to device B.
33
3410. Delete the intermediate keys (keys used for encrypting the key to import) from devices A and B.
35
36```ts
37import { huks } from '@kit.UniversalKeystoreKit';
38
39let IV = '0000000000000000'; // Replace this example code with a random value in practice.
40let AAD = "abababababababab";
41let NONCE = 'hahahahahaha'; // Replace this example code with a random value in practice.
42let TAG_SIZE = 16;
43let FILED_LENGTH = 4;
44let importedAes192PlainKey = "The aes192 key to import";
45let callerAes256Kek = "It's a kek to encrypt aes192 key";
46let callerKeyAlias = "test_caller_key_ecdh_aes192";
47let callerKekAliasAes256 = "test_caller_kek_ecdh_aes256";
48let callerAgreeKeyAliasAes256 = "test_caller_agree_key_ecdh_aes256";
49let importedKeyAliasAes192 = "test_import_key_ecdh_aes192";
50let huksPubKey: Uint8Array;
51let callerSelfPublicKey: Uint8Array;
52let outSharedKey: Uint8Array;
53let outPlainKeyEncData: Uint8Array;
54let outKekEncData: Uint8Array;
55let outKekEncTag: Uint8Array;
56let outAgreeKeyEncTag: Uint8Array;
57let mask = [0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000];
58
59function subUint8ArrayOf(arrayBuf: Uint8Array, start: number, end: number) {
60  let arr: number[] = [];
61  for (let i = start; i < end && i < arrayBuf.length; ++i) {
62    arr.push(arrayBuf[i]);
63  }
64  return new Uint8Array(arr);
65}
66
67function stringToUint8Array(str: string) {
68  let arr: number[] = [];
69  for (let i = 0, j = str.length; i < j; ++i) {
70    arr.push(str.charCodeAt(i));
71  }
72  return new Uint8Array(arr);
73}
74
75function assignLength(length: number, arrayBuf: Uint8Array, startIndex: number) {
76  let index = startIndex;
77  for (let i = 0; i < 4; i++) {
78    arrayBuf[index++] = (length & mask[i]) >> (i * 8);
79  }
80  return 4;
81}
82
83function assignData(data: Uint8Array, arrayBuf: Uint8Array, startIndex: number) {
84  let index = startIndex;
85  for (let i = 0; i < data.length; i++) {
86    arrayBuf[index++] = data[i];
87  }
88  return data.length;
89}
90
91let genWrappingKeyParams: huks.HuksOptions = {
92  properties: new Array<huks.HuksParam>(
93    {
94      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
95      value: huks.HuksKeyAlg.HUKS_ALG_ECC
96    },
97    {
98      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
99      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_UNWRAP
100    },
101    {
102      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
103      value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256
104    },
105    {
106      tag: huks.HuksTag.HUKS_TAG_PADDING,
107      value: huks.HuksKeyPadding.HUKS_PADDING_NONE
108    }
109  )
110}
111let genCallerEcdhParams: huks.HuksOptions = {
112  properties: new Array<huks.HuksParam>(
113    {
114      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
115      value: huks.HuksKeyAlg.HUKS_ALG_ECC
116    },
117    {
118      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
119      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE
120    },
121    {
122      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
123      value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256
124    }
125  )
126}
127let importParamsCallerKek: huks.HuksOptions = {
128  properties: new Array<huks.HuksParam>(
129    {
130      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
131      value: huks.HuksKeyAlg.HUKS_ALG_AES
132    },
133    {
134      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
135      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT
136    },
137    {
138      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
139      value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256
140    },
141    {
142      tag: huks.HuksTag.HUKS_TAG_PADDING,
143      value: huks.HuksKeyPadding.HUKS_PADDING_NONE
144    },
145    {
146      tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
147      value: huks.HuksCipherMode.HUKS_MODE_GCM
148    },
149    {
150      tag: huks.HuksTag.HUKS_TAG_DIGEST,
151      value: huks.HuksKeyDigest.HUKS_DIGEST_NONE
152    },
153    {
154      tag: huks.HuksTag.HUKS_TAG_IV,
155      value: stringToUint8Array(IV)
156    }
157  ),
158  inData: stringToUint8Array(callerAes256Kek)
159}
160let importParamsAgreeKey: huks.HuksOptions = {
161  properties: new Array<huks.HuksParam>(
162    {
163      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
164      value: huks.HuksKeyAlg.HUKS_ALG_AES
165    },
166    {
167      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
168      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT
169    },
170    {
171      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
172      value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256
173    },
174    {
175      tag: huks.HuksTag.HUKS_TAG_PADDING,
176      value: huks.HuksKeyPadding.HUKS_PADDING_NONE
177    },
178    {
179      tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
180      value: huks.HuksCipherMode.HUKS_MODE_GCM
181    },
182    {
183      tag: huks.HuksTag.HUKS_TAG_DIGEST,
184      value: huks.HuksKeyDigest.HUKS_DIGEST_NONE
185    },
186    {
187      tag: huks.HuksTag.HUKS_TAG_IV,
188      value: stringToUint8Array(IV)
189    }
190  ),
191}
192let callerAgreeParams: huks.HuksOptions = {
193  properties: new Array<huks.HuksParam>(
194    {
195      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
196      value: huks.HuksKeyAlg.HUKS_ALG_ECDH
197    },
198    {
199      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
200      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE
201    },
202    {
203      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
204      value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256
205    }
206  )
207}
208let encryptKeyCommonParams: huks.HuksOptions = {
209  properties: new Array<huks.HuksParam>(
210    {
211      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
212      value: huks.HuksKeyAlg.HUKS_ALG_AES
213    },
214    {
215      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
216      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT
217    },
218    {
219      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
220      value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256
221    },
222    {
223      tag: huks.HuksTag.HUKS_TAG_PADDING,
224      value: huks.HuksKeyPadding.HUKS_PADDING_NONE
225    },
226    {
227      tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
228      value: huks.HuksCipherMode.HUKS_MODE_GCM
229    },
230    {
231      tag: huks.HuksTag.HUKS_TAG_NONCE,
232      value: stringToUint8Array(NONCE)
233    },
234    {
235      tag: huks.HuksTag.HUKS_TAG_ASSOCIATED_DATA,
236      value: stringToUint8Array(AAD)
237    }
238  ),
239}
240let importWrappedAes192Params: huks.HuksOptions = {
241  properties: new Array<huks.HuksParam>(
242    {
243      tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
244      value: huks.HuksKeyAlg.HUKS_ALG_AES
245    },
246    {
247      tag: huks.HuksTag.HUKS_TAG_PURPOSE,
248      value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
249      huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
250    },
251    {
252      tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
253      value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_192
254    },
255    {
256      tag: huks.HuksTag.HUKS_TAG_PADDING,
257      value: huks.HuksKeyPadding.HUKS_PADDING_NONE
258    },
259    {
260      tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
261      value: huks.HuksCipherMode.HUKS_MODE_CBC
262    },
263    {
264      tag: huks.HuksTag.HUKS_TAG_DIGEST,
265      value: huks.HuksKeyDigest.HUKS_DIGEST_NONE
266    },
267    {
268      tag: huks.HuksTag.HUKS_TAG_UNWRAP_ALGORITHM_SUITE,
269      value: huks.HuksUnwrapSuite.HUKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING
270    },
271    {
272      tag: huks.HuksTag.HUKS_TAG_IV,
273      value: stringToUint8Array(IV)
274    }
275  )
276}
277
278async function publicGenerateItemFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
279  console.info(`enter promise generateKeyItem`);
280  try {
281    await huks.generateKeyItem(keyAlias, huksOptions)
282      .then(data => {
283        console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`);
284      })
285      .catch((err: Error) => {
286        console.error(`promise: generateKeyItem failed, ${JSON.stringify(err)}`);
287      })
288  } catch (err) {
289    console.error(`promise: generateKeyItem invalid, ${JSON.stringify(err)}`);
290  }
291}
292
293async function publicImportKeyItemFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
294  console.info(`enter promise importKeyItem`);
295  try {
296    await huks.importKeyItem(keyAlias, huksOptions)
297      .then(data => {
298        console.info(`promise: importKeyItem success, data = ${JSON.stringify(data)}`);
299      }).catch((err: Error) => {
300        console.error(`promise: importKeyItem failed, ${JSON.stringify(err)}`);
301      })
302  } catch (err) {
303    console.error(`promise: importKeyItem input arg invalid, ${JSON.stringify(err)}`);
304  }
305}
306
307async function publicDeleteKeyItemFunc(KeyAlias: string, huksOptions: huks.HuksOptions) {
308  console.info(`enter promise deleteKeyItem`);
309  try {
310    await huks.deleteKeyItem(KeyAlias, huksOptions)
311      .then(data => {
312        console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`);
313      })
314      .catch((err: Error) => {
315        console.error(`promise: deleteKeyItem failed, ${JSON.stringify(err)}`);
316      })
317  } catch (err) {
318    console.error(`promise: deleteKeyItem input arg invalid, ${JSON.stringify(err)}`);
319  }
320}
321
322function importWrappedKeyItem(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) {
323  return new Promise<void>((resolve, reject) => {
324    try {
325      huks.importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions, (error, data) => {
326        if (error) {
327          reject(error);
328        } else {
329          resolve(data);
330        }
331      });
332    } catch (error) {
333    }
334  });
335}
336
337async function publicImportWrappedKeyFunc(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) {
338  console.info(`enter promise importWrappedKeyItem`);
339  for (let i = 0; i < huksOptions.inData!.length; i++) {
340    console.info(`${i}: ${huksOptions.inData![i]}`);
341  }
342  try {
343    await importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions)
344      .then((data) => {
345        console.info(`promise: importWrappedKeyItem success, data = ${JSON.stringify(data)}`);
346      })
347      .catch((error: Error) => {
348        console.error(`promise: importWrappedKeyItem failed, ${JSON.stringify(error)}`);
349      });
350  } catch (error) {
351    console.error(`promise: importWrappedKeyItem input arg invalid, ${JSON.stringify(error)}`);
352  }
353}
354
355async function publicInitFunc(srcKeyAlias: string, huksOptions: huks.HuksOptions) {
356  let handle: number = 0;
357  console.info(`enter promise doInit`);
358  try {
359    await huks.initSession(srcKeyAlias, huksOptions)
360      .then((data) => {
361        console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);
362        handle = data.handle;
363      })
364      .catch((error: Error) => {
365        console.error(`promise: doInit key failed, ${JSON.stringify(error)}`);
366      });
367  } catch (error) {
368    console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`);
369  }
370  return handle;
371}
372
373async function publicUpdateSessionFunction(handle: number, huksOptions: huks.HuksOptions) {
374  const maxUpdateSize = 64;
375  const inData = huksOptions.inData!;
376  const lastInDataPosition = inData.length - 1;
377  let inDataSegSize = maxUpdateSize;
378  let inDataSegPosition = 0;
379  let isFinished = false;
380  let outData: number[] = [];
381
382  while (inDataSegPosition <= lastInDataPosition) {
383    if (inDataSegPosition + maxUpdateSize > lastInDataPosition) {
384      isFinished = true;
385      inDataSegSize = lastInDataPosition - inDataSegPosition + 1;
386      console.info(`enter promise doUpdate`);
387      break;
388    }
389    huksOptions.inData = new Uint8Array(
390      Array.from(inData).slice(inDataSegPosition, inDataSegPosition + inDataSegSize)
391    );
392    console.info(`enter promise doUpdate`);
393    try {
394      await huks.updateSession(handle, huksOptions)
395        .then((data) => {
396          console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);
397          outData = outData.concat(Array.from(data.outData!));
398        })
399        .catch((error: Error) => {
400          console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`);
401        });
402    } catch (error) {
403      console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`);
404    }
405    if ((!isFinished) && (inDataSegPosition + maxUpdateSize > lastInDataPosition)) {
406      console.error(`update size invalid isFinished = ${isFinished}`);
407      console.error(`inDataSegPosition = ${inDataSegPosition}`);
408      console.error(`lastInDataPosition = ${lastInDataPosition}`);
409      return;
410    }
411    inDataSegPosition += maxUpdateSize;
412  }
413  return outData;
414}
415
416async function publicFinishSession(handle: number, huksOptions: huks.HuksOptions, inData: number[]) {
417  let outData: number[] = [];
418  console.info(`enter promise doFinish`);
419  try {
420    await huks.finishSession(handle, huksOptions)
421      .then((data) => {
422        console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`);
423        outData = inData.concat(Array.from(data.outData!));
424      })
425      .catch((error: Error) => {
426        console.error(`promise: doFinish key failed, ${JSON.stringify(error)}`);
427      });
428  } catch (error) {
429    console.error(`promise: doFinish input arg invalid, ${JSON.stringify(error)}`);
430  }
431  return new Uint8Array(outData);
432}
433
434async function cipherFunction(keyAlias: string, huksOptions: huks.HuksOptions) {
435  let handle = await publicInitFunc(keyAlias, huksOptions);
436  let tmpData = await publicUpdateSessionFunction(handle, huksOptions);
437  let outData = await publicFinishSession(handle, huksOptions, tmpData!);
438  return outData;
439}
440
441async function agreeFunction(keyAlias: string, huksOptions: huks.HuksOptions, huksPublicKey: Uint8Array) {
442  let handle = await publicInitFunc(keyAlias, huksOptions);
443  let outSharedKey: Uint8Array = new Uint8Array();
444  huksOptions.inData = huksPublicKey;
445  console.info(`enter promise doUpdate`);
446  try {
447    await huks.updateSession(handle, huksOptions)
448      .then((data) => {
449        console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);
450      })
451      .catch((error: Error) => {
452        console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`);
453      });
454  } catch (error) {
455    console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`);
456  }
457  console.info(`enter promise doInit`);
458  try {
459    await huks.finishSession(handle, huksOptions)
460      .then((data) => {
461        console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);
462        outSharedKey = data.outData as Uint8Array;
463      })
464      .catch((error: Error) => {
465        console.error(`promise: doInit key failed, ${JSON.stringify(error)}`);
466      });
467  } catch (error) {
468    console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`);
469  }
470  return outSharedKey;
471}
472
473async function ImportKekAndAgreeSharedSecret(callerKekAlias: string, importKekParams: huks.HuksOptions,
474  callerKeyAlias: string, huksPublicKey: Uint8Array, agreeParams: huks.HuksOptions) {
475  await publicImportKeyItemFunc(callerKekAlias, importKekParams);
476  outSharedKey = await agreeFunction(callerKeyAlias, agreeParams, huksPublicKey);
477  importParamsAgreeKey.inData = outSharedKey;
478  await publicImportKeyItemFunc(callerAgreeKeyAliasAes256, importParamsAgreeKey);
479}
480
481async function generateAndExportPublicKey(keyAlias: string, huksOptions: huks.HuksOptions, caller: Boolean) {
482  await publicGenerateItemFunc(keyAlias, huksOptions);
483  try {
484    await huks.exportKeyItem(keyAlias, huksOptions)
485      .then((data) => {
486        console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`);
487        if (caller) {
488          callerSelfPublicKey = data.outData as Uint8Array;
489        } else {
490          huksPubKey = data.outData as Uint8Array;
491        }
492      })
493      .catch((error: Error) => {
494        console.error(`promise: exportKeyItem failed, ${JSON.stringify(error)}`);
495      });
496  } catch (error) {
497    console.error(`promise: generate pubKey failed, ${JSON.stringify(error)}`);
498  }
499}
500
501async function EncryptImportedPlainKeyAndKek(keyAlias: string) {
502  encryptKeyCommonParams.inData = stringToUint8Array(keyAlias)
503  let plainKeyEncData = await cipherFunction(callerKekAliasAes256, encryptKeyCommonParams);
504  outKekEncTag = subUint8ArrayOf(plainKeyEncData, plainKeyEncData.length - TAG_SIZE, plainKeyEncData.length)
505  outPlainKeyEncData = subUint8ArrayOf(plainKeyEncData, 0, plainKeyEncData.length - TAG_SIZE)
506  encryptKeyCommonParams.inData = stringToUint8Array(callerAes256Kek)
507  let kekEncData = await cipherFunction(callerAgreeKeyAliasAes256, encryptKeyCommonParams)
508  outAgreeKeyEncTag = subUint8ArrayOf(kekEncData, kekEncData.length - TAG_SIZE, kekEncData.length)
509  outKekEncData = subUint8ArrayOf(kekEncData, 0, kekEncData.length - TAG_SIZE)
510}
511
512async function BuildWrappedDataAndImportWrappedKey(plainKey: string) {
513  let plainKeySizeBuff = new Uint8Array(4);
514  assignLength(plainKey.length, plainKeySizeBuff, 0);
515  let wrappedData = new Uint8Array(
516    FILED_LENGTH + huksPubKey.length +
517      FILED_LENGTH + AAD.length +
518      FILED_LENGTH + NONCE.length +
519      FILED_LENGTH + TAG_SIZE +
520      FILED_LENGTH + outKekEncData.length +
521      FILED_LENGTH + AAD.length +
522      FILED_LENGTH + NONCE.length +
523      FILED_LENGTH + TAG_SIZE +
524      FILED_LENGTH + plainKeySizeBuff.length +
525      FILED_LENGTH + outPlainKeyEncData.length
526  );
527  let index = 0;
528  let AADUint8Array = stringToUint8Array(AAD);
529  let NonceArray = stringToUint8Array(NONCE);
530  index += assignLength(callerSelfPublicKey.length, wrappedData, index); // 4
531  index += assignData(callerSelfPublicKey, wrappedData, index); // 91
532  index += assignLength(AADUint8Array.length, wrappedData, index); // 4
533  index += assignData(AADUint8Array, wrappedData, index); // 16
534  index += assignLength(NonceArray.length, wrappedData, index); // 4
535  index += assignData(NonceArray, wrappedData, index); // 12
536  index += assignLength(outAgreeKeyEncTag.length, wrappedData, index); // 4
537  index += assignData(outAgreeKeyEncTag, wrappedData, index); // 16
538  index += assignLength(outKekEncData.length, wrappedData, index); // 4
539  index += assignData(outKekEncData, wrappedData, index); // 32
540  index += assignLength(AADUint8Array.length, wrappedData, index); // 4
541  index += assignData(AADUint8Array, wrappedData, index); // 16
542  index += assignLength(NonceArray.length, wrappedData, index); // 4
543  index += assignData(NonceArray, wrappedData, index); // 12
544  index += assignLength(outKekEncTag.length, wrappedData, index); // 4
545  index += assignData(outKekEncTag, wrappedData, index); // 16
546  index += assignLength(plainKeySizeBuff.length, wrappedData, index); // 4
547  index += assignData(plainKeySizeBuff, wrappedData, index); // 4
548  index += assignLength(outPlainKeyEncData.length, wrappedData, index); // 4
549  index += assignData(outPlainKeyEncData, wrappedData, index); // 24
550  return wrappedData;
551}
552
553/* Simulate the encrypted key import scenario. Import a key from device A (remote device) to device B (local device). */
554async function ImportWrappedKey() {
555  /**
556   * 1. If the key to import 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.
557   * This example uses importedAes192PlainKey (symmetric key) as an example.
558   */
559
560  /* 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. */
561  const srcKeyAliasWrap = 'HUKS_Basic_Capability_Import_0200';
562  await generateAndExportPublicKey(srcKeyAliasWrap, genWrappingKeyParams, false);
563
564  /* 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. */
565  await generateAndExportPublicKey(callerKeyAlias, genCallerEcdhParams, true);
566
567  /**
568   4. Generate a symmetric key Caller_Kek for device A. This key is used to encrypt To_Import_Key.
569   * 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.
570   */
571  await ImportKekAndAgreeSharedSecret(callerKekAliasAes256, importParamsCallerKek, callerKeyAlias, huksPubKey,
572    callerAgreeParams);
573
574  /**
575   * 6. Use Caller_Kek to encrypt To_Import_Key of device A and generate To_Import_Key_Enc.
576   * 7. Use Shared_Key to encrypt Caller_Kek of device A and generate Caller_Kek_Enc.
577   */
578  await EncryptImportedPlainKeyAndKek(importedAes192PlainKey);
579
580  /* 8. Encapsulate the key material Caller_Pk, To_Import_Key_Enc, and Caller_Kek_Enc of device A, and sends it to device B. In this example, Caller_Pk is placed in callerSelfPublicKey, To_Import_Key_Enc in PlainKeyEncData, and Caller_Kek_Enc in KekEncData. */
581  let wrappedData = await BuildWrappedDataAndImportWrappedKey(importedAes192PlainKey);
582  importWrappedAes192Params.inData = wrappedData;
583
584  /* 9. Import the encapsulated key material to device B. */
585  await publicImportWrappedKeyFunc(importedKeyAliasAes192, srcKeyAliasWrap, importWrappedAes192Params);
586
587  /* 10. Delete the intermediate keys (keys used for encrypting the key to import) from devices A and B. */
588  await publicDeleteKeyItemFunc(srcKeyAliasWrap, genWrappingKeyParams);
589  await publicDeleteKeyItemFunc(callerKeyAlias, genCallerEcdhParams);
590  await publicDeleteKeyItemFunc(callerKekAliasAes256, callerAgreeParams);
591}
592
593```
594
595
596## Verification
597
598Use [huks.isKeyItemExist](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksiskeyitemexist9) to check whether the key exists. If the key exists, the key is successfully imported.
599
600```ts
601import { huks } from '@kit.UniversalKeystoreKit';
602
603/*
604 * Set the key alias and encapsulate the key property set.
605 */
606let keyAlias = 'test_import_key_ecdh_aes192';
607let isKeyExist: Boolean;
608let keyProperties: Array<huks.HuksParam> = [{
609  tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
610  value: huks.HuksKeyAlg.HUKS_ALG_AES,
611}];
612let huksOptions: huks.HuksOptions = {
613  properties: keyProperties, // It cannot be empty.
614  inData: new Uint8Array(new Array()) // It cannot be empty.
615}
616try {
617  huks.isKeyItemExist(keyAlias, huksOptions, (error, data) => {
618    if (error) {
619      console.error(`callback: isKeyItemExist failed, ${JSON.stringify(error)}`);
620    } else {
621      if (data !== null && data.valueOf() !== null) {
622        isKeyExist = data.valueOf();
623        console.info(`callback: isKeyItemExist success, isKeyExist = ${isKeyExist}`);
624      }
625    }
626  });
627} catch (error) {
628  console.error(`callback: isKeyItemExist input arg invalid, ${JSON.stringify(error)}`);
629}
630```
631