• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Key Agreement (ArkTS)
2
3
4This 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).
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
13The optional parameter **HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG** specifies how a derived key or a key generated after key agreement is stored.
14
15- **HUKS_STORAGE_ONLY_USED_IN_HUKS**: The key is stored and managed by HUKS.
16
17- **HUKS_STORAGE_KEY_EXPORT_ALLOWED** (default): The key is directly exported to the service and not managed by HUKS.
18
19**Key Export**
20
21Export the public key of the asymmetric key pair of device A and device B. For details, see [Key Export](huks-export-key-arkts.md).
22
23**Key Agreement**
24
25Perform 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 secrete key.
26
27**Key Deletion**
28
29Delete 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).
30
31```ts
32/*
33 * Agree on a 256-bit X25519 key. This example uses promise-based APIs.
34 */
35 import huks from '@ohos.security.huks';
36 import { BusinessError } from '@ohos.base';
37 /*
38  * Set the key alias and encapsulate the key property set.
39  */
40 let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias";
41 let srcKeyAliasSecond = "AgreeX25519KeySecondAlias";
42 let agreeX25519InData = 'AgreeX25519TestIndata';
43 let finishOutData: Uint8Array;
44 let handle: number;
45 let exportKey: Uint8Array;
46 let exportKeyFrist: Uint8Array;
47 let exportKeySecond: Uint8Array;
48 /* Set the parameter set used for generating the key. */
49 let properties: Array<huks.HuksParam> = new Array();
50 properties[0] = {
51     tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
52     value: huks.HuksKeyAlg.HUKS_ALG_X25519,
53 }
54 properties[1] = {
55     tag: huks.HuksTag.HUKS_TAG_PURPOSE,
56     value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE,
57 }
58 properties[2] = {
59     tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
60     value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256,
61 }
62 properties[3] = {
63     tag: huks.HuksTag.HUKS_TAG_DIGEST,
64     value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
65 }
66 properties[4] = {
67     tag: huks.HuksTag.HUKS_TAG_PADDING,
68     value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
69 }
70 properties[5] = {
71     tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
72     value: huks.HuksCipherMode.HUKS_MODE_CBC,
73 }
74 properties[6] = {
75     tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
76     value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
77 }
78 let HuksOptions: huks.HuksOptions = {
79     properties: properties,
80     inData: new Uint8Array(new Array())
81 }
82 /* Set the parameter set for the first key agreement. */
83 let finishProperties: Array<huks.HuksParam> = new Array();
84 finishProperties[0] = {
85     tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG,
86     value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS,
87 }
88 finishProperties[1] = {
89     tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS,
90     value: true
91 }
92 finishProperties[2] = {
93     tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
94     value: huks.HuksKeyAlg.HUKS_ALG_AES,
95 }
96 finishProperties[3] = {
97     tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
98     value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256,
99 }
100 finishProperties[4] = {
101     tag: huks.HuksTag.HUKS_TAG_PURPOSE,
102     value:
103     huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
104     huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT,
105 }
106 finishProperties[5] = {
107     tag: huks.HuksTag.HUKS_TAG_DIGEST,
108     value: huks.HuksKeyDigest.HUKS_DIGEST_NONE,
109 }
110 finishProperties[6] = {
111     tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
112     value: StringToUint8Array(srcKeyAliasFirst+ 'final'),
113 }
114 finishProperties[7] = {
115     tag: huks.HuksTag.HUKS_TAG_PADDING,
116     value: huks.HuksKeyPadding.HUKS_PADDING_NONE,
117 }
118 finishProperties[8] = {
119     tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
120     value: huks.HuksCipherMode.HUKS_MODE_ECB,
121 }
122 let finishOptionsFrist: huks.HuksOptions = {
123     properties: finishProperties,
124     inData: StringToUint8Array(agreeX25519InData)
125 }
126 /* Set the parameter set for the second key agreement. */
127 let finishPropertiesSecond = [...finishProperties]
128 finishPropertiesSecond[6] = {
129    tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS,
130    value: StringToUint8Array(srcKeyAliasSecond + 'final'),
131 }
132 let finishOptionsSecond: huks.HuksOptions = {
133     properties: finishPropertiesSecond,
134     inData: StringToUint8Array(agreeX25519InData)
135 }
136 function StringToUint8Array(str:string) {
137     let arr: number[] = new Array();
138     for (let i = 0, j = str.length; i < j; ++i) {
139         arr.push(str.charCodeAt(i));
140     }
141 return new Uint8Array(arr);
142 }
143 class throwObject {
144     isThrow: boolean = false
145 }
146 /* Generate a key. */
147 function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
148     return new Promise<void>((resolve, reject) => {
149         try {
150             huks.generateKeyItem(keyAlias, huksOptions, (error, data) => {
151                 if (error) {
152                     reject(error);
153                 } else {
154                     resolve(data);
155                 }
156             });
157         } catch (error) {
158             throwObject.isThrow = true;
159             throw(error as Error);
160         }
161     });
162 }
163 /* Call generateKeyItem to generate a key. */
164 async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
165     console.info(`enter promise generateKeyItem`);
166     let throwObject:throwObject = {isThrow: false};
167     try {
168         await generateKeyItem(keyAlias, huksOptions, throwObject)
169         .then((data) => {
170             console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`);
171         })
172         .catch((error: BusinessError) => {
173             if (throwObject.isThrow) {
174                 throw(error as Error);
175             } else {
176                 console.error(`promise: generateKeyItem failed` + error);
177             }
178         });
179     } catch (error) {
180         console.error(`promise: generateKeyItem input arg invalid` + error);
181     }
182 }
183 /* Initializes a key session, which returns a session handle (mandatory) and a challenge (optional). */
184 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
185     return new Promise<huks.HuksSessionHandle>((resolve, reject) => {
186         try {
187             huks.initSession(keyAlias, huksOptions, (error, data) => {
188                 if (error) {
189                     reject(error);
190                 } else {
191                     resolve(data);
192                 }
193             });
194         } catch (error) {
195             throwObject.isThrow = true;
196             throw(error as Error);
197         }
198     });
199 }
200 /* Call initSession. A session handle is returned. */
201 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
202     console.info(`enter promise doInit`);
203     let throwObject: throwObject = {isThrow: false};
204     try {
205         await initSession(keyAlias, huksOptions, throwObject)
206         .then ((data) => {
207             console.info(`promise: doInit success, data = ${JSON.stringify(data)}`);
208             handle = data.handle;
209         })
210         .catch((error: BusinessError) => {
211             if (throwObject.isThrow) {
212                 throw(error as Error);
213             } else {
214                 console.error(`promise: doInit failed` + error);
215             }
216         });
217     } catch (error) {
218         console.error(`promise: doInit input arg invalid` + error);
219     }
220 }
221 /* Call updateSession multiple times to process data by segment and output the processed data. */
222 function updateSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject)  {
223     return new Promise<huks.HuksReturnResult>((resolve, reject) => {
224         try {
225             huks.updateSession(handle, huksOptions, (error, data) => {
226                 if (error) {
227                     reject(error);
228                 } else {
229                     resolve(data);
230                 }
231             });
232         } catch (error) {
233             throwObject.isThrow = true;
234             throw(error as Error);
235         }
236     });
237 }
238 /* Call updateSession to perform key agreement. */
239 async function publicUpdateFunc(handle: number, huksOptions: huks.HuksOptions) {
240     console.info(`enter promise doUpdate`);
241     let throwObject: throwObject = {isThrow: false};
242     try {
243         await updateSession(handle, huksOptions, throwObject)
244         .then ((data) => {
245             console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`);
246         })
247         .catch((error: BusinessError) => {
248             if (throwObject.isThrow) {
249                 throw(error as Error);
250             } else {
251                 console.error(`promise: doUpdate failed` + error);
252             }
253         });
254     } catch (error) {
255         console.error(`promise: doUpdate input arg invalid` + error);
256     }
257 }
258 /* Finish the key session to output the shared secret key. */
259 function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject) {
260     return new Promise<huks.HuksReturnResult>((resolve, reject) => {
261         try {
262             huks.finishSession(handle, huksOptions, (error, data) =>{
263                 if (error) {
264                     reject(error);
265                 } else {
266                     resolve(data);
267                 }
268             });
269         } catch (error) {
270             throwObject.isThrow = true;
271             throw(error as Error);
272         }
273     });
274 }
275 /* Call finishSession to finish the operation. */
276 async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) {
277     console.info(`enter promise doFinish`);
278     let throwObject: throwObject = {isThrow: false};
279     try {
280         await finishSession(handle, huksOptions, throwObject)
281         .then ((data) => {
282             finishOutData = data.outData as Uint8Array;
283             console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`);
284         })
285         .catch((error: BusinessError) => {
286             if (throwObject.isThrow) {
287                 throw(error as Error);
288             } else {
289                 console.error(`promise: doFinish failed` + error);
290             }
291         });
292     } catch (error) {
293         console.error(`promise: doFinish input arg invalid` + error);
294     }
295 }
296 /* Export a key. */
297 function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
298     return new Promise<huks.HuksReturnResult>((resolve, reject) => {
299         try {
300             huks.exportKeyItem(keyAlias, huksOptions, (error, data) => {
301                 if (error) {
302                     reject(error);
303                 } else {
304                     resolve(data);
305                 }
306             });
307         } catch (error) {
308             throwObject.isThrow = true;
309             throw(error as Error);
310         }
311     });
312 }
313 /* Call exportKeyItem to export the public key. */
314 async function publicExportKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
315     console.info(`enter promise export`);
316     let throwObject: throwObject = {isThrow: false};
317     try {
318         await exportKeyItem(keyAlias, huksOptions, throwObject)
319         .then ((data) => {
320             console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`);
321             exportKey = data.outData as Uint8Array;
322         })
323         .catch((error: BusinessError) => {
324             if (throwObject.isThrow) {
325                 throw(error as Error);
326             } else {
327                 console.error(`promise: exportKeyItem failed` + error);
328             }
329         });
330     } catch (error) {
331         console.error(`promise: exportKeyItem input arg invalid` + error);
332     }
333 }
334 /* Delete the keys. */
335 function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) {
336     return new Promise<void>((resolve, reject) => {
337         try {
338             huks.deleteKeyItem(keyAlias, huksOptions, (error, data) => {
339                 if (error) {
340                     reject(error);
341                 } else {
342                     resolve(data);
343                 }
344             });
345         } catch (error) {
346             throwObject.isThrow = true;
347             throw(error as Error);
348         }
349     });
350 }
351 /* Call deleteKeyItem to delete a key. */
352 async function publicDeleteKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) {
353     console.info(`enter promise deleteKeyItem`);
354     let throwObject: throwObject = {isThrow: false};
355     try {
356         await deleteKeyItem(keyAlias, huksOptions, throwObject)
357         .then ((data) => {
358            console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`);
359         })
360         .catch((error :BusinessError) => {
361             if (throwObject.isThrow) {
362                 throw(error as Error);
363             } else {
364                 console.error(`promise: deleteKeyItem failed` + error);
365             }
366         });
367     } catch (error) {
368         console.error(`promise: deletKeeyItem input arg invalid` + error);
369     }
370 }
371 async function testAgree() {
372     /* 1. Set the key alias srcKeyAliasFirst for device A and srcKeyAliasSecond for device B, and parameters for generating the key pairs. */
373     /* 2. Generate an asymmetric key pair for device A. */
374     await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions);
375     /* 3. Generate an asymmetric key pair for device B. */
376     await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions);
377     /* 4. Export the public keys of the key pairs of device A and device B. */
378     await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions);
379     exportKeyFrist = exportKey;
380     await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions);
381     exportKeySecond = exportKey;
382     /* 5. Perform key agreement (Init-Update-Finish) for device A. */
383     await publicInitFunc(srcKeyAliasFirst, HuksOptions);
384     HuksOptions.inData = exportKeySecond;
385     await publicUpdateFunc(handle, HuksOptions);
386     await publicFinishFunc(handle, finishOptionsFrist);
387     /* 5. Perform key agreement (Init-Update-Finish) for device B. */
388     await publicInitFunc(srcKeyAliasSecond, HuksOptions);
389     HuksOptions.inData = exportKeyFrist;
390     await publicUpdateFunc(handle, HuksOptions);
391     await publicFinishFunc(handle, finishOptionsSecond);
392     /* 6. Delete keys from device A and device B. */
393     await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions);
394     await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions);
395 }
396```
397