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