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