• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Key Agreement (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 uses X25519 and DH as an example to demonstrate how to perform key agreement for HUKS-managed keys. For details about the scenarios and supported algorithms, see [Supported Algorithms](huks-key-generation-overview.md#supported-algorithms).
11
12## How to Develop
13
14**Key Generation**
15
16Generate an asymmetric key for device A and device B each. For details, see [Key Generation](huks-key-generation-overview.md) or [Key Import](huks-key-import-overview.md).
17
18(Optional) You can specify the [HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG](../../reference/apis-universal-keystore-kit/capi-native-huks-type-h.md#oh_huks_keystoragetype) parameter when generating a key to decide if HUKS manages the resulting key from the key agreement process.
19
20- If this tag is set to **HUKS_STORAGE_ONLY_USED_IN_HUKS**, the shared secret is managed by HUKS. That is, the shared secret is always in a secure environment throughout its lifecycle.
21
22- If this tag is set to **HUKS_STORAGE_KEY_EXPORT_ALLOWED**, the shared secret generated will be returned to the caller for management. That is, service side ensures the key security.
23
24- If this tag is not set, the shared secret generated can be either managed by HUKS or returned to the caller for management. The key protection mode can be set in the subsequent key agreement on the service side.
25
26**Key Export**
27
28Export the public key of the asymmetric key pair of device A and device B. For details, see [Key Export](huks-export-key-arkts.md).
29
30**Key Agreement**
31
32Perform key agreement using the public key of the peer device and private key of the local device (that is, public key of device B and private key of device A for device A, and public key of device A and private key of device B for device B) to produce a shared secret.
33
34During key agreement, you can set **HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** (optional) to specify how the shared secret generated is managed.
35
36| Key Generation| Key Agreement| Specifications|
37| -------- | -------- | -------- |
38| HUKS_STORAGE_ONLY_USED_IN_HUKS | HUKS_STORAGE_ONLY_USED_IN_HUKS | The key is managed by HUKS.|
39| HUKS_STORAGE_KEY_EXPORT_ALLOWED | HUKS_STORAGE_KEY_EXPORT_ALLOWED | The key is returned to the caller for management.|
40| The tag is not set.| HUKS_STORAGE_ONLY_USED_IN_HUKS | The key is managed by HUKS.|
41| The tag is not set.| HUKS_STORAGE_KEY_EXPORT_ALLOWED | The key is returned to the caller for management.|
42| The tag is not set.| The tag is not set.| The key is returned to the caller for management.|
43
44Note: The tag value set in key agreement should not conflict with the tag value set in key generation. The above table lists only valid settings.
45
46**Key Deletion**
47
48Delete the keys from device A and device B when the keys are not required. For details, see [Deleting a Key](huks-delete-key-arkts.md).
49
50
51The following uses X25519 and DH key agreement as examples.
52### X25519 asymmetric key agreement example
53  ```ts
54  /*
55  * Agree on an X25519 key using promise-based APIs.
56  */
57  import { huks } from '@kit.UniversalKeystoreKit';
58
59  function StringToUint8Array(str: string) {
60    let arr: number[] = new Array();
61    for (let i = 0, j = str.length; i < j; ++i) {
62      arr.push(str.charCodeAt(i));
63    }
64    return new Uint8Array(arr);
65  }
66
67  /*
68  * Set the key alias and encapsulate the key property set.
69  */
70  let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias";
71  let srcKeyAliasSecond = "AgreeX25519KeySecondAlias";
72  let agreeX25519InData = 'AgreeX25519TestIndata';
73  let finishOutData: Uint8Array;
74  let handle: number;
75  let exportKey: Uint8Array;
76  let exportKeyFirst: Uint8Array;
77  let exportKeySecond: Uint8Array;
78  /* Set the parameter set used for generating the key. */
79  let properties: Array<huks.HuksParam> = [{
80    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
81    value: huks.HuksKeyAlg.HUKS_ALG_X25519,
82  }, {
83    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
84    value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
85  }, {
86    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
87    value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256,
88  }, {
89    tag: huks.HuksTag.HUKS_TAG_DIGEST,
90    value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
91  }, {
92    tag: huks.HuksTag.HUKS_TAG_PADDING,
93    value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
94  }, {
95    tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
96    value: huks.HuksCipherMode.HUKS_MODE_CBC,
97  }, {
98    tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
99    value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
100  }];
101  let HuksOptions: huks.HuksOptions = {
102    properties: properties,
103    inData: new Uint8Array(new Array())
104  }
105  /* Set the parameter set for the first key agreement. */
106  const finishProperties: Array<huks.HuksParam> = [{
107    tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
108    value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
109  }, {
110    tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
111    value: true
112  }, {
113    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
114    value: huks.HuksKeyAlg.HUKS_ALG_AES,
115  }, {
116    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
117    value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
118  }, {
119    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
120    value:
121    huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
122    huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
123  }, {
124    tag: huks.HuksTag.HUKS_TAG_DIGEST,
125    value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
126  }, {
127    tag: huks.HuksTag.HUKS_TAG_PADDING,
128    value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
129  }, {
130    tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
131    value: huks.HuksCipherMode.HUKS_MODE_ECB,
132  }];
133  let finishOptionsFirst: huks.HuksOptions = {
134    properties: [
135      ...finishProperties, {
136      tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
137      value: StringToUint8Array(srcKeyAliasFirst + 'final'),
138    }],
139    inData: StringToUint8Array(agreeX25519InData)
140  }
141  /* Set the parameter set for the second key agreement. */
142  let finishOptionsSecond: huks.HuksOptions = {
143    properties: [
144      ...finishProperties, {
145      tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
146      value: StringToUint8Array(srcKeyAliasSecond + 'final'),
147    }],
148    inData: StringToUint8Array(agreeX25519InData)
149  }
150
151  class ThrowObject {
152    isThrow: boolean = false
153  }
154
155  /* Generate a key. */
156  function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: ThrowObject) {
157    return new Promise<void>((resolve, reject) => {
158      try {
159        huks.generateKeyItem(keyAlias, huksOptions, (error, data) => {
160          if (error) {
161            reject(error);
162          } else {
163            resolve(data);
164          }
165        });
166      } catch (error) {
167        throwObject.isThrow = true;
168        throw (error as Error);
169      }
170    });
171  }
172
173  /* Call generateKeyItem to generate a key. */
174  async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
175    console.info(`enter promise generateKeyItem`);
176    let throwObject: ThrowObject = { isThrow: false };
177    try {
178      await generateKeyItem(keyAlias, huksOptions, throwObject)
179        .then((data) => {
180          console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`);
181        })
182        .catch((error: Error) => {
183          if (throwObject.isThrow) {
184            throw (error as Error);
185          } else {
186            console.error(`promise: generateKeyItem failed, ${JSON.stringify(error)}`);
187          }
188        });
189    } catch (error) {
190      console.error(`promise: generateKeyItem input arg invalid, ${JSON.stringify(error)}`);
191    }
192  }
193
194  /* Initializes a key session, which returns a session handle (mandatory) and a challenge (optional). */
195  function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: ThrowObject) {
196    return new Promise<huks.HuksSessionHandle>((resolve, reject) => {
197      try {
198        huks.initSession(keyAlias, huksOptions, (error, data) => {
199          if (error) {
200            reject(error);
201          } else {
202            resolve(data);
203          }
204        });
205      } catch (error) {
206        throwObject.isThrow = true;
207        throw (error as Error);
208      }
209    });
210  }
211
212  /* Call initSession. A session handle is returned. */
213  async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
214    console.info(`enter promise doInit`);
215    let throwObject: ThrowObject = { isThrow: false };
216    try {
217      await initSession(keyAlias, huksOptions, throwObject)
218        .then((data) => {
219          console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);
220          handle = data.handle;
221        })
222        .catch((error: Error) => {
223          if (throwObject.isThrow) {
224            throw (error as Error);
225          } else {
226            console.error(`promise: doInit failed, ${JSON.stringify(error)}`);
227          }
228        });
229    } catch (error) {
230      console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`);
231    }
232  }
233
234  /* Call updateSession multiple times to process data by segment and output the processed data. */
235  function updateSession(handle: number, huksOptions: huks.HuksOptions, throwObject: ThrowObject) {
236    return new Promise<huks.HuksReturnResult>((resolve, reject) => {
237      try {
238        huks.updateSession(handle, huksOptions, (error, data) => {
239          if (error) {
240            reject(error);
241          } else {
242            resolve(data);
243          }
244        });
245      } catch (error) {
246        throwObject.isThrow = true;
247        throw (error as Error);
248      }
249    });
250  }
251
252  /* Call updateSession to perform key agreement. */
253  async function publicUpdateFunc(handle: number, huksOptions: huks.HuksOptions) {
254    console.info(`enter promise doUpdate`);
255    let throwObject: ThrowObject = { isThrow: false };
256    try {
257      await updateSession(handle, huksOptions, throwObject)
258        .then((data) => {
259          console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);
260        })
261        .catch((error: Error) => {
262          if (throwObject.isThrow) {
263            throw (error as Error);
264          } else {
265            console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`);
266          }
267        });
268    } catch (error) {
269      console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`);
270    }
271  }
272
273  /* Finish the key session to output the shared secret key. */
274  function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: ThrowObject) {
275    return new Promise<huks.HuksReturnResult>((resolve, reject) => {
276      try {
277        huks.finishSession(handle, huksOptions, (error, data) => {
278          if (error) {
279            reject(error);
280          } else {
281            resolve(data);
282          }
283        });
284      } catch (error) {
285        throwObject.isThrow = true;
286        throw (error as Error);
287      }
288    });
289  }
290
291  /* Call finishSession to finish the operation. */
292  async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) {
293    console.info(`enter promise doFinish`);
294    let throwObject: ThrowObject = { isThrow: false };
295    try {
296      await finishSession(handle, huksOptions, throwObject)
297        .then((data) => {
298          finishOutData = data.outData as Uint8Array;
299          console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`);
300        })
301        .catch((error: Error) => {
302          if (throwObject.isThrow) {
303            throw (error as Error);
304          } else {
305            console.error(`promise: doFinish failed, ${JSON.stringify(error)}`);
306          }
307        });
308    } catch (error) {
309      console.error(`promise: doFinish input arg invalid, ${JSON.stringify(error)}`);
310    }
311  }
312
313  /* Export a key. */
314  function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: ThrowObject) {
315    return new Promise<huks.HuksReturnResult>((resolve, reject) => {
316      try {
317        huks.exportKeyItem(keyAlias, huksOptions, (error, data) => {
318          if (error) {
319            reject(error);
320          } else {
321            resolve(data);
322          }
323        });
324      } catch (error) {
325        throwObject.isThrow = true;
326        throw (error as Error);
327      }
328    });
329  }
330
331  /* Call exportKeyItem to export the public key. */
332  async function publicExportKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
333    console.info(`enter promise export`);
334    let throwObject: ThrowObject = { isThrow: false };
335    try {
336      await exportKeyItem(keyAlias, huksOptions, throwObject)
337        .then((data) => {
338          console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`);
339          exportKey = data.outData as Uint8Array;
340        })
341        .catch((error: Error) => {
342          if (throwObject.isThrow) {
343            throw (error as Error);
344          } else {
345            console.error(`promise: exportKeyItem failed, ${JSON.stringify(error)}`);
346          }
347        });
348    } catch (error) {
349      console.error(`promise: exportKeyItem input arg invalid, ${JSON.stringify(error)}`);
350    }
351  }
352
353  /* Delete the keys. */
354  function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: ThrowObject) {
355    return new Promise<void>((resolve, reject) => {
356      try {
357        huks.deleteKeyItem(keyAlias, huksOptions, (error, data) => {
358          if (error) {
359            reject(error);
360          } else {
361            resolve(data);
362          }
363        });
364      } catch (error) {
365        throwObject.isThrow = true;
366        throw (error as Error);
367      }
368    });
369  }
370
371  /* Call deleteKeyItem to delete a key. */
372  async function publicDeleteKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
373    console.info(`enter promise deleteKeyItem`);
374    let throwObject: ThrowObject = { isThrow: false };
375    try {
376      await deleteKeyItem(keyAlias, huksOptions, throwObject)
377        .then((data) => {
378          console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`);
379        })
380        .catch((error: Error) => {
381          if (throwObject.isThrow) {
382            throw (error as Error);
383          } else {
384            console.error(`promise: deleteKeyItem failed, ${JSON.stringify(error)}`);
385          }
386        });
387    } catch (error) {
388      console.error(`promise: deleteKeyItem input arg invalid, ${JSON.stringify(error)}`);
389    }
390  }
391
392  async function testAgree() {
393    /* 1. Set the key alias srcKeyAliasFirst for device A and srcKeyAliasSecond for device B, and parameters for generating the key pairs. */
394    /* 2. Generate an asymmetric key pair for device A. */
395    await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions);
396    /* 3. Generate an asymmetric key pair for device B. */
397    await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions);
398    /* 4. Export the public keys of the key pairs of device A and device B. */
399    await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions);
400    exportKeyFirst = exportKey;
401    await publicExportKeyFunc(srcKeyAliasSecond, HuksOptions);
402    exportKeySecond = exportKey;
403    /* 5. Perform key agreement (Init-Update-Finish) for device A. */
404    await publicInitFunc(srcKeyAliasFirst, HuksOptions);
405    HuksOptions.inData = exportKeySecond;
406    await publicUpdateFunc(handle, HuksOptions);
407    await publicFinishFunc(handle, finishOptionsFirst);
408    /* 5. Perform key agreement (Init-Update-Finish) for device B. */
409    await publicInitFunc(srcKeyAliasSecond, HuksOptions);
410    HuksOptions.inData = exportKeyFirst;
411    await publicUpdateFunc(handle, HuksOptions);
412    await publicFinishFunc(handle, finishOptionsSecond);
413    /* 6. Delete keys from device A and device B. */
414    await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions);
415    await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions);
416  }
417  ```
418
419### DH key agreement example
420
421  ```ts
422  /*
423  * Agree on a DH key using promise-based APIs.
424  */
425  import { huks } from '@kit.UniversalKeystoreKit';
426
427  function StringToUint8Array(str: string) {
428    let arr: number[] = []
429    for (let i = 0, j = str.length; i < j; ++i) {
430      arr.push(str.charCodeAt(i))
431    }
432    return new Uint8Array(arr)
433  }
434
435  function Uint8ArrayToBigInt(arr: Uint8Array): bigint {
436    let i = 0
437    const byteMax: bigint = BigInt('0x100')
438    let result: bigint = BigInt('0')
439    while (i < arr.length) {
440      result = result * byteMax
441      result = result + BigInt(arr[i])
442      i += 1
443    }
444    return result
445  }
446
447  const dhAgree: Array<huks.HuksParam> = [{
448    tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
449    value: huks.HuksKeyAlg.HUKS_ALG_DH,
450  }, {
451    tag: huks.HuksTag.HUKS_TAG_PURPOSE,
452    value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
453  }]
454  const dh2048Agree: Array<huks.HuksParam> = [
455    ...dhAgree, {
456    tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
457    value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048,
458  }]
459  const dhGenOptions: huks.HuksOptions = {
460    properties: dh2048Agree,
461    inData: new Uint8Array([])
462  }
463  const emptyOptions: huks.HuksOptions = {
464    properties: [],
465    inData: new Uint8Array([])
466  }
467
468  async function HuksDhAgreeExportKey(keyAlias: string,
469    peerPubKey: huks.HuksReturnResult): Promise<huks.HuksReturnResult> {
470    const initHandle = await huks.initSession(keyAlias, dhGenOptions)
471    const dhAgreeUpdateBobPubKey: huks.HuksOptions = {
472      properties: [
473        ...dh2048Agree, {
474        tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
475        value: huks.HuksKeyStorageType.HUKS_STORAGE_KEY_EXPORT_ALLOWED,
476      }],
477      inData: peerPubKey.outData
478    }
479    await huks.updateSession(initHandle.handle, dhAgreeUpdateBobPubKey)
480    return await huks.finishSession(initHandle.handle, emptyOptions)
481  }
482
483  async function HuksDhAgreeExportTest(
484    aliasA: string, aliasB: string,
485    pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult) {
486
487    const agreedKeyFromAlice = await HuksDhAgreeExportKey(aliasA, pubKeyB)
488    console.info(`ok! agreedKeyFromAlice export is 0x${Uint8ArrayToBigInt(agreedKeyFromAlice.outData).toString(16)}`)
489
490    const agreedKeyFromBob = await HuksDhAgreeExportKey(aliasB, pubKeyA)
491    console.info(`ok! agreedKeyFromBob export is 0x${Uint8ArrayToBigInt(agreedKeyFromBob.outData).toString(16)}`)
492  }
493
494  async function HuksDhAgreeInHuks(keyAlias: string, peerPubKey: huks.HuksReturnResult,
495    aliasAgreedKey: string): Promise<huks.HuksReturnResult> {
496    const onlyUsedInHuks: Array<huks.HuksParam> = [{
497      tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG,
498      value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
499    }, {
500      tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
501      value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
502    }]
503    const dhAgreeInit: huks.HuksOptions = {
504      properties: [
505        ...dhAgree,
506        { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, },
507        ...onlyUsedInHuks],
508      inData: new Uint8Array([])
509    }
510    const dhAgreeFinishParams: Array<huks.HuksParam> = [
511      ...onlyUsedInHuks,
512      { tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, value: true },
513      { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, value: huks.HuksKeyAlg.HUKS_ALG_AES },
514      { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 },
515      {
516        tag: huks.HuksTag.HUKS_TAG_PURPOSE,
517        value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
518      }]
519
520    const handle = await huks.initSession(keyAlias, dhAgreeInit)
521    const dhAgreeUpdatePubKey: huks.HuksOptions = {
522      properties: [...dhAgree, ...onlyUsedInHuks],
523      inData: peerPubKey.outData
524    }
525    await huks.updateSession(handle.handle, dhAgreeUpdatePubKey)
526    const dhAgreeAliceFinnish: huks.HuksOptions = {
527      properties: [...dhAgreeFinishParams, {
528        tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, value: StringToUint8Array(aliasAgreedKey)
529      }], inData: new Uint8Array([])
530    }
531    return await huks.finishSession(handle.handle, dhAgreeAliceFinnish)
532  }
533
534  async function HuksDhAgreeInHuksTest(
535    aliasA: string, aliasB: string,
536    pubKeyA: huks.HuksReturnResult, pubKeyB: huks.HuksReturnResult,
537    aliasAgreedKeyFromA: string, aliasAgreedKeyFromB: string) {
538
539    const finishAliceResult = await HuksDhAgreeInHuks(aliasA, pubKeyB, aliasAgreedKeyFromA)
540    console.info(`ok! finishAliceResult in huks is 0x${Uint8ArrayToBigInt(finishAliceResult.outData).toString(16)}`)
541    const aliceAgreedExist = await huks.isKeyItemExist(aliasAgreedKeyFromA, emptyOptions)
542    console.info(`ok! aliceAgreedExist in huks is ${aliceAgreedExist}`)
543
544    const finishBobResult = await HuksDhAgreeInHuks(aliasB, pubKeyA, aliasAgreedKeyFromB)
545    console.info(`ok! finishBobResult in huks is 0x${Uint8ArrayToBigInt(finishBobResult.outData).toString(16)}`)
546    const bobAgreedExist = await huks.isKeyItemExist(aliasAgreedKeyFromB, emptyOptions)
547    console.info(`ok! bobAgreedExist in huks is ${bobAgreedExist}`)
548
549    await huks.deleteKeyItem(aliasAgreedKeyFromA, emptyOptions)
550    await huks.deleteKeyItem(aliasAgreedKeyFromB, emptyOptions)
551  }
552
553  export default async function HuksDhAgreeTest() {
554    const aliasAlice = 'alice'
555    const aliasBob = 'bob'
556
557    /* Call generateKeyItem to generate a key with alias of alice and a key with alias of bob. */
558    await huks.generateKeyItem(aliasAlice, dhGenOptions)
559    await huks.generateKeyItem(aliasBob, dhGenOptions)
560
561    /* Export the public keys of asymmetric key pairs alice and bob. */
562    const pubKeyAlice = await huks.exportKeyItem(aliasAlice, emptyOptions)
563    const pubKeyBob = await huks.exportKeyItem(aliasBob, emptyOptions)
564
565    /* Perform key agreement and return the shared secret generated to the caller for management. */
566    await HuksDhAgreeExportTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob)
567
568    /* Perform key agreement and let HUKS manage the shared secret generated. */
569    await HuksDhAgreeInHuksTest(aliasAlice, aliasBob, pubKeyAlice, pubKeyBob, 'agreedKeyFromAlice', 'agreedKeyFromBob')
570
571    await huks.deleteKeyItem(aliasAlice, emptyOptions)
572    await huks.deleteKeyItem(aliasBob, emptyOptions)
573  }
574  ```
575