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