1 2# HUKS Development (ArkTS) 3 4> **NOTE** 5> 6> The SDK of API version 9 or later must be used. 7 8## Key Generation 9 10The OpenHarmony Universal KeyStore (HUKS) provides key management and cryptography operations for services. For a key generated by the HUKS, the plaintext will never be exposed outside throughout the lifecycle. No one can obtain the key in plaintext. Even the service itself can call APIs provided by the HUKS to perform operations on the key and obtain the operation result, but cannot access the key. 11 12**How to Develop** 13 14Use [huks.generateKeyItem(keyAlias,options,callback)](../reference/apis/js-apis-huks.md#huksgeneratekeyitem9) to generate a key. You need to pass in the key alias in **keyAlias**, key property set in **options**, and **callback** to return the result asynchronously. For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). 15 16**Procedure** 171. Set the key alias. 182. Initialize the key property set.<br>Use [HuksParam](../reference/apis/js-apis-huks.md#huksparam) to encapsulate key properties and use a **HuksParam** array to assign values to the **properties** field of [HuksOptions](../reference/apis/js-apis-huks.md#huksoptions). The parameters [HuksKeyAlg](../reference/apis/js-apis-huks.md#hukskeyalg), [HuksKeySize](../reference/apis/js-apis-huks.md#hukskeysize), and [HuksKeyPurpose](../reference/apis/js-apis-huks.md#hukskeypurpose) are mandatory. 193. Pass in the key alias and key parameter set to generate a key. 20 21> **NOTE** 22> 23> The key alias cannot exceed 64 bytes. 24 25**Sample code** 26 27```ts 28/* 29 * Generate a DH key using callback-based APIs. 30 */ 31import huks from '@ohos.security.huks'; 32import { BusinessError } from '@ohos.base'; 33 34class HuksProperties { 35 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 36 value: huks.HuksKeyAlg | huks.HuksKeySize | huks.HuksKeyPurpose | huks.HuksKeyDigest = huks.HuksKeyAlg.HUKS_ALG_ECC; 37} 38 39/* 40 * Set the key alias and encapsulate the key properties. 41 */ 42let keyAlias = 'dh_key'; 43let properties1: HuksProperties[] = [ 44 { 45 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 46 value: huks.HuksKeyAlg.HUKS_ALG_DH 47 }, 48 { 49 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 50 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE 51 }, 52 { 53 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 54 value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048 55 }, 56 { 57 tag: huks.HuksTag.HUKS_TAG_DIGEST, 58 value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 59 } 60]; 61 62let huksOptions: huks.HuksOptions = { 63 properties: properties1, 64 inData: new Uint8Array(new Array()) 65} 66 67/* 68 * Generate a key. 69 */ 70function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions){ 71 return new Promise<void>((resolve, reject) => { 72 try { 73 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 74 if (error) { 75 reject(error); 76 } else { 77 resolve(data); 78 } 79 }); 80 } catch (error) { 81 throw (error as Error); 82 } 83 }); 84} 85 86async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 87 console.info(`enter callback generateKeyItem`); 88 try { 89 await generateKeyItem(keyAlias, huksOptions) 90 .then((data) => { 91 console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); 92 }) 93 .catch((error: BusinessError) => { 94 console.error(`callback: generateKeyItem failed`); 95 }); 96 } catch (error) { 97 console.error(`callback: generateKeyItem input arg invalid`); 98 } 99} 100 101async function TestGenKey() { 102 await publicGenKeyFunc(keyAlias, huksOptions); 103} 104``` 105 106## Key Import 107 108A key generated outside the HUKS (for example, generated through key agreement or by a server) can be imported to the HUKS for management. The HUKS supports import of keys in plaintext. However, if a key is imported in plaintext, the key is exposed in the Rich Execution Environment (REE) memory. This type of import applies to lightweight devices or security-insensitive services. For security-sensitive services, use the secure import feature provided by the HUKS. Secure import allows the keys generated for services to be transferred to the HUKS through an end-to-end encrypted transmission channel. 109 110Once a key is imported to the HUKS, its plaintext will never be exposed outside the HUKS throughout the lifecycle of the key. 111 112### Importing a Key in Plaintext 113 114Use [huks.importKeyItem(keyAlias,options,callback)](../reference/apis/js-apis-huks.md#huksimportkeyitem9) to import a key in plaintext. You need to pass in the key alias in **keyAlias**, key material and property set in **options**, and **callback** to return the result asynchronously. For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). 115 1161. Set the key alias. 1172. Encapsulate the key material and key property set.<br>The key material must comply with [HUKS key material formats](./huks-appendix.md#key-material-formats). The **inData** value of [HuksOptions](../reference/apis/js-apis-huks.md#huksoptions) must be in the Uint8Array format. Encapsulate key properties in [HuksParam](../reference/apis/js-apis-huks.md#huksparam), and use a **HuksParam** array to assign values to the **properties** field. The key properties must contain [HuksKeyAlg](../reference/apis/js-apis-huks.md#hukskeyalg), [HuksKeySize](../reference/apis/js-apis-huks.md#hukskeysize), and [HuksKeyPurpose](../reference/apis/js-apis-huks.md#hukskeypurpose). 1183. Import the key. 119 120**Sample code** 121 122```ts 123import huks from '@ohos.security.huks' 124 125/* 126 /* Import an AES key of 256 bits. */ 127 */ 128 129/* Key */ 130let plainTextSize32 = new Uint8Array([ 131 0xfb, 0x8b, 0x9f, 0x12, 0xa0, 0x83, 0x19, 0xbe, 0x6a, 0x6f, 0x63, 0x2a, 0x7c, 0x86, 0xba, 0xca, 132 0x64, 0x0b, 0x88, 0x96, 0xe2, 0xfa, 0x77, 0xbc, 0x71, 0xe3, 0x0f, 0x0f, 0x9e, 0x3c, 0xe5, 0xf9 133]); 134 135/* 136 * Set the key alias. 137 */ 138let keyAlias = 'AES256Alias_sample'; 139 140/* 141 * Encapsulate the key properties and key material. 142 */ 143class propertyType { 144 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 145 value: huks.HuksKeyAlg | huks.HuksKeySize | huks.HuksKeyPurpose = huks.HuksKeyAlg.HUKS_ALG_RSA; 146} 147 148let properties: propertyType[] = [ 149 { 150 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 151 value:huks.HuksKeyAlg.HUKS_ALG_AES 152 }, 153 { 154 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 155 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 156 }, 157 { 158 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 159 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 160 }, 161] 162 163let options: huks.HuksOptions = { 164 properties: properties, 165 inData: plainTextSize32 166}; 167 168/* 169 * Import the key. 170 */ 171try { 172 huks.importKeyItem(keyAlias, options, (error, data) => { 173 if (error) { 174 console.error(`callback: importKeyItem failed`); 175 } else { 176 console.info(`callback: importKeyItem success`); 177 } 178 }); 179} catch (error) { 180 console.error(`callback: importKeyItem input arg invalid`); 181} 182``` 183 184**Verification** 185 186Check whether the key exists. If yes, the key is imported successfully. 187 188**Sample code** 189 190```ts 191import huks from '@ohos.security.huks'; 192 193let keyAlias = 'AES256Alias_sample'; 194let isKeyExist = false; 195 196class keyPropertyType { 197 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 198 value: huks.HuksKeyAlg = huks.HuksKeyAlg.HUKS_ALG_RSA; 199} 200 201let keyProperties: keyPropertyType[] = [ 202 { 203 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 204 value: huks.HuksKeyAlg.HUKS_ALG_AES 205 }, 206] 207 208let huksOptions: huks.HuksOptions = { 209 properties: keyProperties, // It cannot be empty. 210 inData: new Uint8Array(new Array()) // It cannot be empty. 211} 212try { 213 huks.isKeyItemExist(keyAlias, huksOptions, (error, data) => { 214 if (error) { 215 console.error(`callback: isKeyItemExist failed`); 216 } else { 217 if (data !== null && data.valueOf() !== null) { 218 isKeyExist = data.valueOf(); 219 console.info(`callback: isKeyItemExist success, isKeyExist = ${isKeyExist}`); 220 } 221 } 222 }); 223} catch (error) { 224 console.error(`callback: isKeyItemExist input arg invalid`); 225} 226``` 227 228### Importing a Key Securely 229 230Compared with import of a key in plaintext, secure import involves more complex key material and operations. The following figure illustrates the basic development process of secure import. 231 232**Figure 1** Development process of secure import 233 234 235 236**Available APIs** 237 238You need to use the APIs listed in the following table in sequence. For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). 239 240**Table 1** APIs for importing a key securely 241 242| API | Description | 243| -------------------------------------- | ----------------------------| 244|generateKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback\<void>) : void| Generates a key.| 245|exportKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback\<HuksReturnResult>) : void| Exports the public key of a key pair.| 246|importWrappedKeyItem(keyAlias: string, wrappingKeyAlias: string, options: HuksOptions, callback: AsyncCallback\<void>) : void|Imports a wrapped key.| 247|deleteKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback\<void>) : void|Deletes a key.| 248 249>**NOTE** 250> 251>The public key plaintext material returned by **exportKeyItem()** is encapsulated in X.509 format, and the key material to be imported by **importWrappedKeyItem()** must be encapsulated in **Length<sub>Data</sub>-Data** format. Specifically, the application needs to request a Uint8Array and encapsulate the Uint8Array in the sequence listed in the following table. 252 253**Table 2** Format of the encrypted key material 254 255| Content| Public Key Length (L<sub>pk2</sub>)| Public Key (pk2)| k2 AAD Length (L<sub>AAD2</sub>)| k2 AAD (AAD2)| k2 Nonce Length (L<sub>Nonce2</sub>)| k2 Nonce (Nonce2)| 256| :--: |:----:|:----: |:----: | :----: | :----:|:----:| 257|Length| 4 bytes|L<sub>pk2</sub> bytes| 4 bytes| L<sub>AAD2</sub> bytes| 4 bytes| L<sub>Nonce2</sub> bytes| 258| Content| k2 AEAD Length (L<sub>AEAD2</sub>)| k2 AEAD (AEAD2)| k3 Ciphertext Length (L<sub>k3_enc</sub>)| k3 Ciphertext (k3_enc)| k3 AAD Length (L<sub>AAD3</sub>)| k3 AAD (AAD3)| 259|Length| 4 bytes|L<sub>AEAD2</sub> bytes| 4 bytes| L<sub>k3_enc</sub> bytes| 4 bytes| L<sub>AAD3</sub> bytes| 260| Content| k3 Nonce Length (L<sub>Nonce3</sub>)| k3 Nonce (Nonce3)| k3 AEAD Length (L<sub>AEAD3</sub>)| k3 AEAD (AEAD3)| Length of **k1'_size** (L<sub>k1'_size</sub>)| Key Plaintext Material Length (k1'_size)| 261|Length| 4 bytes|L<sub>Nonce3</sub> bytes| 4 bytes| L<sub>AEAD3</sub> bytes| 4 bytes| L<sub>k1'_size</sub> bytes| 262|Content|k1' Ciphertext Length (L<sub>k1'_enc</sub>)| k1' ciphertext (k1'_enc) | | | | | 263|Length| 4 bytes|L<sub>k1'_enc</sub> bytes| | | | | 264 265**How to Develop** 266 267The following example presents the development involving HUKS APIs (using the ECDH key agreement suite). The operations performed by the service are not included. 268 2691. Generate the **Caller_Key** and **Wrapping_Key** asymmetric key pairs. 2702. Export the public key material. 2713. Generate a symmetric key **Caller_Kek**. 2724. Perform key agreement using the public keys of **Caller_Key** and **Wrapping_Key** to obtain the **Agree_Key**. 2735. Use **Caller_Kek** to encrypt the key to be imported. 2746. Use **Agree_Key** to encrypt **Caller_Kek**. 2757. Encapsulate the key material to be imported. 2768. Import the encapsulated key material. 2779. Delete the keys that are used for secure import. 278 279**Sample code** 280 281```ts 282import huks from '@ohos.security.huks'; 283import { BusinessError } from '@ohos.base'; 284 285let IV = '0000000000000000'; 286let AAD = "abababababababab"; 287let NONCE = "hahahahahaha"; 288let TAG_SIZE = 16; 289let FILED_LENGTH = 4; 290let importedAes192PlainKey = "The aes192 key to import"; 291let callerAes256Kek = "The is kek to encrypt aes192 key"; 292 293let callerKeyAlias = "test_caller_key_ecdh_aes192"; 294let callerKekAliasAes256 = "test_caller_kek_ecdh_aes256"; 295let callerAgreeKeyAliasAes256 = "test_caller_agree_key_ecdh_aes256"; 296let importedKeyAliasAes192 = "test_import_key_ecdh_aes192"; 297 298let huksPubKey: Uint8Array; 299let callerSelfPublicKey: Uint8Array; 300let outSharedKey: Uint8Array; 301let outPlainKeyEncData: Uint8Array; 302let outKekEncData: Uint8Array; 303let outKekEncTag: Uint8Array; 304let outAgreeKeyEncTag: Uint8Array; 305 306let mask = [0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000]; 307function subUint8ArrayOf(arrayBuf: Uint8Array, start: number, end: number) { 308 let arr: number[] = []; 309 for (let i = start; i < end && i < arrayBuf.length; ++i) { 310 arr.push(arrayBuf[i]); 311 } 312 return new Uint8Array(arr); 313} 314 315function stringToUint8Array(str: string) { 316 let arr: number[] = []; 317 for (let i = 0, j = str.length; i < j; ++i) { 318 arr.push(str.charCodeAt(i)); 319 } 320 return new Uint8Array(arr); 321} 322 323function assignLength(length: number, arrayBuf: Uint8Array, startIndex: number) { 324 let index = startIndex; 325 for (let i = 0; i < 4; i++) { 326 arrayBuf[index++] = (length & mask[i]) >> (i * 8); 327 } 328 return 4; 329} 330 331function assignData(data: Uint8Array, arrayBuf: Uint8Array, startIndex: number) { 332 let index = startIndex; 333 for (let i = 0; i < data.length; i++) { 334 arrayBuf[index++] = data[i]; 335 } 336 return data.length; 337} 338 339 340let genWrappingKeyParams:huks.HuksOptions = { 341 properties: new Array<huks.HuksParam>( 342 { 343 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 344 value: huks.HuksKeyAlg.HUKS_ALG_ECC 345 }, 346 { 347 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 348 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_UNWRAP 349 }, 350 { 351 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 352 value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256 353 }, 354 { 355 tag: huks.HuksTag.HUKS_TAG_PADDING, 356 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 357 } 358 ) 359} 360 361let genCallerEcdhParams:huks.HuksOptions = { 362 properties: new Array<huks.HuksParam>( 363 { 364 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 365 value: huks.HuksKeyAlg.HUKS_ALG_ECC 366 }, 367 { 368 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 369 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE 370 }, 371 { 372 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 373 value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256 374 } 375 ) 376} 377 378let importParamsCallerKek: huks.HuksOptions = { 379 properties: new Array<huks.HuksParam>( 380 { 381 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 382 value: huks.HuksKeyAlg.HUKS_ALG_AES 383 }, 384 { 385 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 386 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 387 }, 388 { 389 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 390 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 391 }, 392 { 393 tag: huks.HuksTag.HUKS_TAG_PADDING, 394 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 395 }, 396 { 397 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 398 value: huks.HuksCipherMode.HUKS_MODE_GCM 399 }, 400 { 401 tag: huks.HuksTag.HUKS_TAG_DIGEST, 402 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE 403 }, 404 { 405 tag: huks.HuksTag.HUKS_TAG_IV, 406 value: stringToUint8Array(IV) 407 } 408 ), 409 inData: stringToUint8Array(callerAes256Kek) 410} 411 412let importParamsAgreeKey: huks.HuksOptions = { 413 properties: new Array<huks.HuksParam>( 414 { 415 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 416 value: huks.HuksKeyAlg.HUKS_ALG_AES 417 }, 418 { 419 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 420 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 421 }, 422 { 423 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 424 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 425 }, 426 { 427 tag: huks.HuksTag.HUKS_TAG_PADDING, 428 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 429 }, 430 { 431 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 432 value: huks.HuksCipherMode.HUKS_MODE_GCM 433 }, 434 { 435 tag: huks.HuksTag.HUKS_TAG_DIGEST, 436 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE 437 }, 438 { 439 tag: huks.HuksTag.HUKS_TAG_IV, 440 value: stringToUint8Array(IV) 441 } 442 ), 443} 444 445let callerAgreeParams: huks.HuksOptions = { 446 properties: new Array<huks.HuksParam>( 447 { 448 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 449 value: huks.HuksKeyAlg.HUKS_ALG_ECDH 450 }, 451 { 452 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 453 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE 454 }, 455 { 456 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 457 value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256 458 } 459 ) 460} 461 462let encryptKeyCommonParams: huks.HuksOptions = { 463 properties: new Array<huks.HuksParam>( 464 { 465 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 466 value: huks.HuksKeyAlg.HUKS_ALG_AES 467 }, 468 { 469 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 470 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 471 }, 472 { 473 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 474 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 475 }, 476 { 477 tag: huks.HuksTag.HUKS_TAG_PADDING, 478 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 479 }, 480 { 481 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 482 value: huks.HuksCipherMode.HUKS_MODE_GCM 483 }, 484 { 485 tag: huks.HuksTag.HUKS_TAG_NONCE, 486 value: stringToUint8Array(NONCE) 487 }, 488 { 489 tag: huks.HuksTag.HUKS_TAG_ASSOCIATED_DATA, 490 value: stringToUint8Array(AAD) 491 } 492 ), 493} 494 495let importWrappedAes192Params: huks.HuksOptions = { 496 properties: new Array<huks.HuksParam>( 497 { 498 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 499 value: huks.HuksKeyAlg.HUKS_ALG_AES 500 }, 501 { 502 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 503 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | 504 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 505 }, 506 { 507 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 508 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_192 509 }, 510 { 511 tag: huks.HuksTag.HUKS_TAG_PADDING, 512 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 513 }, 514 { 515 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 516 value: huks.HuksCipherMode.HUKS_MODE_CBC 517 }, 518 { 519 tag: huks.HuksTag.HUKS_TAG_DIGEST, 520 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE 521 }, 522 { 523 tag: huks.HuksTag.HUKS_TAG_UNWRAP_ALGORITHM_SUITE, 524 value: huks.HuksUnwrapSuite.HUKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING 525 }, 526 { 527 tag: huks.HuksTag.HUKS_TAG_IV, 528 value: stringToUint8Array(IV) 529 } 530 ) 531} 532 533async function publicGenerateItemFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 534 console.info(`enter promise generateKeyItem`); 535 try { 536 await huks.generateKeyItem(keyAlias, huksOptions) 537 .then(data => { 538 console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`); 539 }) 540 .catch((err: BusinessError) => { 541 console.error(`callback: generateKeyItem failed`); 542 }) 543 } catch (err) { 544 console.error(`callback: generateKeyItem invalid`); 545 } 546} 547 548async function publicImportKeyItemFunc(keyAlias: string, HuksOptions: huks.HuksOptions) { 549 console.info(`enter promise importKeyItem`); 550 try { 551 await huks.importKeyItem(keyAlias, HuksOptions) 552 .then(data => { 553 console.info(`promise: importKeyItem success, data = ${JSON.stringify(data)}`); 554 }).catch((err: BusinessError) => { 555 console.error(`promise: importKeyItem failed`); 556 }) 557 } catch (err) { 558 console.error(`promise: importKeyItem input arg invalid`); 559 } 560} 561 562async function publicDeleteKeyItemFunc(KeyAlias: string, HuksOptions: huks.HuksOptions) { 563 console.info(`enter promise deleteKeyItem`); 564 try { 565 await huks.deleteKeyItem(KeyAlias, HuksOptions) 566 .then(data => { 567 console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`); 568 }) 569 .catch((err: BusinessError) => { 570 console.error(`promise: deleteKeyItem failed`); 571 }) 572 } catch (err) { 573 console.error(`promise: deleteKeyItem input arg invalid`); 574 } 575} 576 577function importWrappedKeyItem(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) { 578 return new Promise<void>((resolve, reject) => { 579 try { 580 huks.importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions, (error, data) => { 581 if (error) { 582 reject(error); 583 } else { 584 resolve(data); 585 } 586 }); 587 } catch (error) { 588 } 589 }); 590} 591 592async function publicImportWrappedKeyFunc(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) { 593 console.info(`enter callback importWrappedKeyItem`); 594 for (let i = 0; i < huksOptions.inData!.length; i++) { 595 console.error(`${i}: ${huksOptions.inData![i]}`); 596 } 597 try { 598 await importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions) 599 .then((data) => { 600 console.info(`callback: importWrappedKeyItem success, data = ${JSON.stringify(data)}`); 601 }) 602 .catch((error: BusinessError) => { 603 console.error(`callback: importWrappedKeyItem failed`); 604 }); 605 } catch (error) { 606 console.error(`callback: importWrappedKeyItem input arg invalid`); 607 } 608} 609 610async function publicImportWrappedKeyPromise(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) { 611 console.info(`enter callback importWrappedKeyItem`); 612 try { 613 await huks.importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions) 614 .then((data) => { 615 console.info(`callback: importWrappedKeyItem success, data = ${JSON.stringify(data)}`); 616 }) 617 .catch((error: BusinessError) => { 618 console.error(`callback: importWrappedKeyItem failed`); 619 }); 620 } catch (error) { 621 console.error(`callback: importWrappedKeyItem input arg invalid`); 622 } 623} 624 625async function publicInitFunc(srcKeyAlias: string, HuksOptions: huks.HuksOptions) { 626 let handle: number = 0; 627 console.info(`enter promise doInit`); 628 try { 629 await huks.initSession(srcKeyAlias, HuksOptions) 630 .then((data) => { 631 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 632 handle = data.handle; 633 }) 634 .catch((error: BusinessError) => { 635 console.error(`promise: doInit key failed`); 636 }); 637 } catch (error) { 638 console.error(`promise: doInit input arg invalid`); 639 } 640 return handle; 641} 642 643async function publicUpdateSessionFunction(handle: number, HuksOptions: huks.HuksOptions) { 644 const maxUpdateSize = 64; 645 const inData = HuksOptions.inData!; 646 const lastInDataPosition = inData.length - 1; 647 let inDataSegSize = maxUpdateSize; 648 let inDataSegPosition = 0; 649 let isFinished = false; 650 let outData: number[] = []; 651 652 while (inDataSegPosition <= lastInDataPosition) { 653 if (inDataSegPosition + maxUpdateSize > lastInDataPosition) { 654 isFinished = true; 655 inDataSegSize = lastInDataPosition - inDataSegPosition + 1; 656 console.error(`enter promise doUpdate`); 657 break; 658 } 659 HuksOptions.inData = new Uint8Array( 660 Array.from(inData).slice(inDataSegPosition, inDataSegPosition + inDataSegSize) 661 ); 662 console.error(`enter promise doUpdate`); 663 try { 664 await huks.updateSession(handle, HuksOptions) 665 .then((data) => { 666 console.error(`promise: doUpdate success, data = ${JSON.stringify(data)}`); 667 outData = outData.concat(Array.from(data.outData!)); 668 }) 669 .catch((error: BusinessError) => { 670 console.error(`promise: doUpdate failed`); 671 }); 672 } catch (error) { 673 console.error(`promise: doUpdate input arg invalid`); 674 } 675 if ((!isFinished) && (inDataSegPosition + maxUpdateSize > lastInDataPosition)) { 676 console.log(`update size invalid isFinished = ${isFinished}`); 677 console.log(`inDataSegPosition = ${inDataSegPosition}`); 678 console.log(`lastInDataPosition = ${lastInDataPosition}`); 679 return; 680 } 681 inDataSegPosition += maxUpdateSize; 682 } 683 return outData; 684} 685 686async function publicFinishSession(handle: number, HuksOptions: huks.HuksOptions, inData: number[]) { 687 let outData: number[] = []; 688 console.info(`enter promise doFinish`); 689 try { 690 await huks.finishSession(handle, HuksOptions) 691 .then((data) => { 692 console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`); 693 outData = inData.concat(Array.from(data.outData!)); 694 }) 695 .catch((error: BusinessError) => { 696 console.error(`promise: doFinish key failed`); 697 }); 698 } catch (error) { 699 console.error(`promise: doFinish input arg invalid`); 700 } 701 return new Uint8Array(outData); 702} 703 704async function cipherFunction(keyAlias: string, HuksOptions: huks.HuksOptions) { 705 let handle = await publicInitFunc(keyAlias, HuksOptions); 706 let tmpData = await publicUpdateSessionFunction(handle, HuksOptions); 707 let outData = await publicFinishSession(handle, HuksOptions, tmpData!); 708 return outData; 709} 710 711async function agreeFunction(keyAlias: string, HuksOptions: huks.HuksOptions, huksPublicKey: Uint8Array) { 712 let handle = await publicInitFunc(keyAlias, HuksOptions); 713 let outSharedKey: Uint8Array = new Uint8Array; 714 HuksOptions.inData = huksPublicKey; 715 console.error(`enter promise doUpdate`); 716 try { 717 await huks.updateSession(handle, HuksOptions) 718 .then((data) => { 719 console.error(`promise: doUpdate success, data = ${JSON.stringify(data)}`); 720 }) 721 .catch((error: BusinessError) => { 722 console.error(`promise: doUpdate failed`); 723 }); 724 } catch (error) { 725 console.error(`promise: doUpdate input arg invalid`); 726 } 727 console.info(`enter promise doInit`); 728 try { 729 await huks.finishSession(handle, HuksOptions) 730 .then((data) => { 731 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 732 outSharedKey = data.outData as Uint8Array; 733 }) 734 .catch((error: BusinessError) => { 735 console.error(`promise: doInit key failed`); 736 }); 737 } catch (error) { 738 console.error(`promise: doInit input arg invalid`); 739 } 740 return outSharedKey; 741} 742 743async function ImportKekAndAgreeSharedSecret(callerKekAlias: string, importKekParams: huks.HuksOptions, callerKeyAlias: string, huksPublicKey: Uint8Array, agreeParams: huks.HuksOptions) { 744 await publicImportKeyItemFunc(callerKekAlias, importKekParams); 745 outSharedKey = await agreeFunction(callerKeyAlias, agreeParams, huksPublicKey); 746 747 importParamsAgreeKey.inData = outSharedKey; 748 await publicImportKeyItemFunc(callerAgreeKeyAliasAes256, importParamsAgreeKey); 749} 750 751async function generateAndExportPublicKey(keyAlias: string, HuksOptions: huks.HuksOptions, caller: Boolean) { 752 await publicGenerateItemFunc(keyAlias, HuksOptions); 753 try { 754 await huks.exportKeyItem(keyAlias, HuksOptions) 755 .then((data) => { 756 console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`); 757 if (caller) { 758 callerSelfPublicKey = data.outData as Uint8Array; 759 } else { 760 huksPubKey = data.outData as Uint8Array; 761 } 762 }) 763 .catch((error: BusinessError) => { 764 console.error(`promise: exportKeyItem failed`); 765 }); 766 } catch (e) { 767 console.error(`promise: generate pubKey failed`); 768 } 769} 770 771async function EncryptImportedPlainKeyAndKek(keyAlias: string) { 772 encryptKeyCommonParams.inData = stringToUint8Array(keyAlias) 773 let plainKeyEncData = await cipherFunction(callerKekAliasAes256, encryptKeyCommonParams); 774 outKekEncTag = subUint8ArrayOf(plainKeyEncData, plainKeyEncData.length - TAG_SIZE, plainKeyEncData.length) 775 outPlainKeyEncData = subUint8ArrayOf(plainKeyEncData, 0, plainKeyEncData.length - TAG_SIZE) 776 777 encryptKeyCommonParams.inData = stringToUint8Array(callerAes256Kek) 778 let kekEncData = await cipherFunction(callerAgreeKeyAliasAes256, encryptKeyCommonParams) 779 outAgreeKeyEncTag = subUint8ArrayOf(kekEncData, kekEncData.length - TAG_SIZE, kekEncData.length) 780 outKekEncData = subUint8ArrayOf(kekEncData, 0, kekEncData.length - TAG_SIZE) 781} 782 783async function BuildWrappedDataAndImportWrappedKey(plainKey: string) { 784 let plainKeySizeBuff = new Uint8Array(4); 785 assignLength(plainKey.length, plainKeySizeBuff, 0); 786 787 let wrappedData = new Uint8Array( 788 FILED_LENGTH + huksPubKey.length + 789 FILED_LENGTH + AAD.length + 790 FILED_LENGTH + NONCE.length + 791 FILED_LENGTH + TAG_SIZE + 792 FILED_LENGTH + outKekEncData.length + 793 FILED_LENGTH + AAD.length + 794 FILED_LENGTH + NONCE.length + 795 FILED_LENGTH + TAG_SIZE + 796 FILED_LENGTH + plainKeySizeBuff.length + 797 FILED_LENGTH + outPlainKeyEncData.length 798 ); 799 let index = 0; 800 let AADUint8Array = stringToUint8Array(AAD); 801 let NonceArray = stringToUint8Array(NONCE); 802 803 index += assignLength(callerSelfPublicKey.length, wrappedData, index); // 4 804 index += assignData(callerSelfPublicKey, wrappedData, index); // 91 805 index += assignLength(AADUint8Array.length, wrappedData, index); // 4 806 index += assignData(AADUint8Array, wrappedData, index); // 16 807 index += assignLength(NonceArray.length, wrappedData, index); // 4 808 index += assignData(NonceArray, wrappedData, index); // 12 809 index += assignLength(outAgreeKeyEncTag.length, wrappedData, index); // 4 810 index += assignData(outAgreeKeyEncTag, wrappedData, index); // 16 811 index += assignLength(outKekEncData.length, wrappedData, index); // 4 812 index += assignData(outKekEncData, wrappedData, index); // 32 813 index += assignLength(AADUint8Array.length, wrappedData, index); // 4 814 index += assignData(AADUint8Array, wrappedData, index); // 16 815 index += assignLength(NonceArray.length, wrappedData, index); // 4 816 index += assignData(NonceArray, wrappedData, index); // 12 817 index += assignLength(outKekEncTag.length, wrappedData, index); // 4 818 index += assignData(outKekEncTag, wrappedData, index); // 16 819 index += assignLength(plainKeySizeBuff.length, wrappedData, index); // 4 820 index += assignData(plainKeySizeBuff, wrappedData, index); // 4 821 index += assignLength(outPlainKeyEncData.length, wrappedData, index); // 4 822 index += assignData(outPlainKeyEncData, wrappedData, index); // 24 823 824 return wrappedData; 825} 826 827async function ImportWrappedKey() { 828 const srcKeyAliesWrap = 'HUKS_Basic_Capability_Import_0200'; 829 /* 830 * Generate Caller_Key and Wrapping_Key, which are used to agree on a key for encrypting the key to be imported, and export the public key materials. 831 */ 832 await generateAndExportPublicKey(srcKeyAliesWrap, genWrappingKeyParams, false); 833 await generateAndExportPublicKey(callerKeyAlias, genCallerEcdhParams, true); 834 835 /** 836 * Generate a symmetric key **Caller_Kek**. 837 * Perform key agreement using the public keys of **Caller_Key** and **Wrapping_Key** to obtain the **Agree_Key**. 838 */ 839 await ImportKekAndAgreeSharedSecret(callerKekAliasAes256, importParamsCallerKek, callerKeyAlias, huksPubKey, callerAgreeParams); 840 841 /** 842 * Use **Caller_Kek** to encrypt the key to be imported. 843 * Use **Agree_Key** to encrypt **Caller_Kek**. 844 */ 845 await EncryptImportedPlainKeyAndKek(importedAes192PlainKey); 846 847 /** 848 * Encapsulate the key materials to be imported. 849 */ 850 let wrappedData = await BuildWrappedDataAndImportWrappedKey(importedAes192PlainKey); 851 importWrappedAes192Params.inData = wrappedData; 852 853 /** 854 * Import the encapsulated key material. 855 */ 856 await publicImportWrappedKeyFunc(importedKeyAliasAes192, srcKeyAliesWrap, importWrappedAes192Params); 857 858 /** 859 * Delete the key used for secure import. 860 */ 861 await publicDeleteKeyItemFunc(srcKeyAliesWrap, genWrappingKeyParams); 862 await publicDeleteKeyItemFunc(callerKeyAlias, genCallerEcdhParams); 863 await publicDeleteKeyItemFunc(importedKeyAliasAes192, importWrappedAes192Params); 864 await publicDeleteKeyItemFunc(callerKekAliasAes256, callerAgreeParams); 865} 866``` 867 868**Verification** 869 870Check whether the key exists. If yes, the key is imported successfully. 871 872**Sample code** 873 874```ts 875import huks from '@ohos.security.huks'; 876 877/* 878 * Set the key alias and encapsulate the key properties. 879 */ 880let keyAlias = 'test_import_key_ecdh_aes192'; 881let isKeyExist:Boolean; 882 883let keyProperties: Array<huks.HuksParam> = new Array(); 884keyProperties[0] = { 885 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 886 value: huks.HuksKeyAlg.HUKS_ALG_AES, 887} 888let huksOptions:huks.HuksOptions = { 889 properties: keyProperties, // It cannot be empty. 890 inData: new Uint8Array(new Array()) // It cannot be empty. 891} 892try { 893 huks.isKeyItemExist(keyAlias, huksOptions, (error, data)=> { 894 if (error) { 895 console.error(`callback: isKeyItemExist failed`); 896 } else { 897 if (data !== null && data.valueOf() !== null) { 898 isKeyExist = data.valueOf(); 899 console.info(`callback: isKeyItemExist success, isKeyExist = ${isKeyExist}`); 900 } 901 } 902 }); 903} catch (error) { 904 console.error(`callback: isKeyItemExist input arg invalid`); 905} 906``` 907 908## Common Key Operations 909 910**When to Use** 911 912To ensure data confidentiality and integrity, you may need to encrypt or decrypt data, generate or verify a signature, perform key agreement, and derive a key. The following describes common key operations. The following examples do not involve secondary identity access control. If secondary identity access control is involved, see [Key Access Control](#key-access-control). 913 914**General Development Process** 915 916The HUKS operates data based on key sessions. The general process is as follows: 917 9181. (Mandatory) Use [huks.initSession()](../reference/apis/js-apis-huks.md#huksinitsession9) to initialize a key session.<br>You need to pass in the key alias and key operation parameters to initialize a key session, and obtain the session handle. The key operation parameters must contain the parameters required by the cipher algorithm, including the cipher algorithm, key size, key purpose, working mode, padding mode, hash mode, IV, nonce, and AAD. If access control is set for the key, other parameters are required. For details, see [Key Access Control](#key-access-control). 9192. (Optional) Use [huks.updateSession()](../reference/apis/js-apis-huks.md#huksupdatesession9) to pass in data by segment. Perform this step only if the data exceeds 100 KB or the cryptographic algorithm requires operations by data segment. Otherwise, skip this step. 9203. (Mandatory) Use [huks.finishSession()](../reference/apis/js-apis-huks.md#huksfinishsession9) to complete the key session operation.<br>Pass in the last data segment and complete the key session operation. If an error occurs during the process or the data passed in is not required, use [huks.abortSession()](../reference/apis/js-apis-huks.md#huksabortsession9) to abort the session. 921 922### Encryption and Decryption 923 924```ts 925/* 926 * The following uses an AES 128-bit key and callback-based APIs as an example. 927 */ 928import huks from '@ohos.security.huks'; 929import { BusinessError } from '@ohos.base'; 930 931let aesKeyAlias = 'test_aesKeyAlias'; 932let handle:number; 933let plainText = '123456'; 934let IV = '001122334455'; 935let cipherData:Uint8Array; 936 937function StringToUint8Array(str: String) { 938 let arr:number[]=new Array(); 939 for (let i = 0, j = str.length; i < j; ++i) { 940 arr.push(str.charCodeAt(i)); 941 } 942 return new Uint8Array(arr); 943} 944 945function Uint8ArrayToString(fileData:Uint8Array) { 946 let dataString = ''; 947 for (let i = 0; i < fileData.length; i++) { 948 dataString += String.fromCharCode(fileData[i]); 949 } 950 return dataString; 951} 952 953function GetAesGenerateProperties() { 954 let properties: Array<huks.HuksParam> = new Array(); 955 let index = 0; 956 properties[index++] = { 957 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 958 value: huks.HuksKeyAlg.HUKS_ALG_AES 959 }; 960 properties[index++] = { 961 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 962 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128 963 }; 964 properties[index++] = { 965 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 966 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | 967 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 968 } 969 return properties; 970} 971 972function GetAesEncryptProperties() { 973 let properties: Array<huks.HuksParam> = new Array(); 974 let index = 0; 975 properties[index++] = { 976 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 977 value: huks.HuksKeyAlg.HUKS_ALG_AES 978 }; 979 properties[index++] = { 980 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 981 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128 982 }; 983 properties[index++] = { 984 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 985 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 986 } 987 properties[index++] = { 988 tag: huks.HuksTag.HUKS_TAG_PADDING, 989 value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 990 } 991 properties[index++] = { 992 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 993 value: huks.HuksCipherMode.HUKS_MODE_CBC 994 } 995 properties[index++] = { 996 tag: huks.HuksTag.HUKS_TAG_IV, 997 value: StringToUint8Array(IV) 998 } 999 return properties; 1000} 1001 1002function GetAesDecryptProperties() { 1003 let properties: Array<huks.HuksParam> = new Array(); 1004 let index = 0; 1005 properties[index++] = { 1006 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1007 value: huks.HuksKeyAlg.HUKS_ALG_AES 1008 }; 1009 properties[index++] = { 1010 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1011 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128 1012 }; 1013 properties[index++] = { 1014 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1015 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 1016 } 1017 properties[index++] = { 1018 tag: huks.HuksTag.HUKS_TAG_PADDING, 1019 value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 1020 } 1021 properties[index++] = { 1022 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 1023 value: huks.HuksCipherMode.HUKS_MODE_CBC 1024 } 1025 properties[index++] = { 1026 tag: huks.HuksTag.HUKS_TAG_IV, 1027 value: StringToUint8Array(IV) 1028 } 1029 return properties; 1030} 1031 1032async function GenerateAesKey() { 1033 let genProperties = GetAesGenerateProperties(); 1034 let options: huks.HuksOptions = { 1035 properties: genProperties 1036 } 1037 await huks.generateKeyItem(aesKeyAlias, options) 1038 .then((data) => { 1039 console.info(`callback: generate AES Key success, data = ${JSON.stringify(data)}`); 1040 }).catch((error: BusinessError)=>{ 1041 console.error(`callback: generate AES Key failed`); 1042 }) 1043} 1044 1045 1046async function EncryptData() { 1047 let encryptProperties = GetAesEncryptProperties(); 1048 let options: huks.HuksOptions = { 1049 properties: encryptProperties, 1050 inData: StringToUint8Array(plainText) 1051 } 1052 await huks.initSession(aesKeyAlias, options) 1053 .then((data) => { 1054 handle = data.handle; 1055 }).catch((error: BusinessError)=>{ 1056 console.error(`callback: init encryptdata failed`); 1057 }) 1058 await huks.finishSession(handle, options) 1059 .then((data) => { 1060 console.info(`callback: encrypt data success, data is `+ Uint8ArrayToString(data.outData as Uint8Array)); 1061 cipherData = data.outData as Uint8Array; 1062 }).catch((error: BusinessError)=>{ 1063 console.error(`callback: encrypt data failed`); 1064 }) 1065} 1066 1067async function DecryptData() { 1068 let decryptOptions = GetAesDecryptProperties() 1069 let options: huks.HuksOptions = { 1070 properties: decryptOptions, 1071 inData: cipherData 1072 } 1073 await huks.initSession(aesKeyAlias, options) 1074 .then((data) => { 1075 handle = data.handle; 1076 }).catch((error: BusinessError)=>{ 1077 console.error(`callback: init decryptdata failed`); 1078 }) 1079 await huks.finishSession(handle, options) 1080 .then((data) => { 1081 console.info(`callback: decrypt data success, data is ` + Uint8ArrayToString(data.outData as Uint8Array)); 1082 }).catch((error: BusinessError)=>{ 1083 console.error(`callback: decrypt data failed`); 1084 }) 1085} 1086 1087async function DeleteKey() { 1088 let emptyOptions: huks.HuksOptions = { 1089 properties: [] 1090 } 1091 await huks.deleteKeyItem(aesKeyAlias, emptyOptions) 1092 .then((data) => { 1093 console.info(`callback: delete data success`); 1094 }).catch((error: BusinessError)=>{ 1095 console.error(`callback: delete data failed`); 1096 }) 1097} 1098``` 1099 1100### Key Agreement 1101 1102You are advised to pass in [HuksKeyStorageType](../reference/apis/js-apis-huks.md#hukskeystoragetype) to specify the storage type in key agreement. From API version 10, only **HUKS_STORAGE_ONLY_USED_IN_HUKS** or **HUKS_STORAGE_KEY_EXPORT_ALLOWED** can be used. If **HuksKeyStorageType** is not passed in, the key can be stored or exported by default, which poses security risks. 1103 1104```ts 1105/* 1106 * Perform key agreement using an X25519 256-bit TEMP key and return the result in a callback. 1107 */ 1108import huks from '@ohos.security.huks'; 1109import { BusinessError } from '@ohos.base'; 1110 1111/* 1112 * Set the key alias and encapsulate the key properties. 1113 */ 1114let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias"; 1115let srcKeyAliasSecond = "AgreeX25519KeySecondAlias"; 1116let agreeX25519InData = 'AgreeX25519TestIndata'; 1117let finishOutData : Uint8Array; 1118let handle: number; 1119let exportKey : Uint8Array; 1120let exportKeyFrist: Uint8Array; 1121let exportKeySecond : Uint8Array; 1122 1123/* Configure the parameter set used for generating the key. */ 1124let properties : Array<huks.HuksParam> = new Array(); 1125properties[0] = { 1126 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1127 value: huks.HuksKeyAlg.HUKS_ALG_X25519, 1128} 1129properties[1] = { 1130 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1131 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE, 1132} 1133properties[2] = { 1134 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1135 value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256, 1136} 1137properties[3] = { 1138 tag: huks.HuksTag.HUKS_TAG_DIGEST, 1139 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, 1140} 1141properties[4] = { 1142 tag: huks.HuksTag.HUKS_TAG_PADDING, 1143 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 1144} 1145properties[5] = { 1146 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 1147 value: huks.HuksCipherMode.HUKS_MODE_CBC, 1148} 1149properties[6] = { 1150 tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, 1151 value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS, 1152} 1153let HuksOptions : huks.HuksOptions = { 1154 properties: properties, 1155 inData: new Uint8Array(new Array()) 1156} 1157 1158/* Configure parameters for the first key agreement. */ 1159let finishProperties : Array<huks.HuksParam> = new Array(); 1160finishProperties[0] = { 1161 tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, 1162 value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS, 1163} 1164finishProperties[1] = { 1165 tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, 1166 value: true 1167} 1168finishProperties[2] = { 1169 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1170 value: huks.HuksKeyAlg.HUKS_ALG_AES, 1171} 1172finishProperties[3] = { 1173 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1174 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, 1175} 1176finishProperties[4] = { 1177 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1178 value: 1179 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | 1180 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 1181} 1182finishProperties[5] = { 1183 tag: huks.HuksTag.HUKS_TAG_DIGEST, 1184 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, 1185} 1186finishProperties[6] = { 1187 tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, 1188 value: StringToUint8Array(srcKeyAliasFirst+ 'final'), 1189} 1190finishProperties[7] = { 1191 tag: huks.HuksTag.HUKS_TAG_PADDING, 1192 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 1193} 1194finishProperties[8] = { 1195 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 1196 value: huks.HuksCipherMode.HUKS_MODE_ECB, 1197} 1198let finishOptionsFrist : huks.HuksOptions = { 1199 properties: finishProperties, 1200 inData: StringToUint8Array(agreeX25519InData) 1201} 1202/* Configure parameters for the second key agreement. */ 1203let finishOptionsSecond : huks.HuksOptions = { 1204 properties: finishProperties, 1205 inData: StringToUint8Array(agreeX25519InData) 1206} 1207finishOptionsSecond.properties!.splice(6, 1, { 1208 tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, 1209 value: StringToUint8Array(srcKeyAliasSecond + 'final'), 1210}) 1211 1212function StringToUint8Array(str:string) { 1213 let arr: number[] = new Array(); 1214 for (let i = 0, j = str.length; i < j; ++i) { 1215 arr.push(str.charCodeAt(i)); 1216 } 1217return new Uint8Array(arr); 1218} 1219class throwObject { 1220 isThrow: boolean = false 1221} 1222function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1223 return new Promise<void>((resolve, reject) => { 1224 try { 1225 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 1226 if (error) { 1227 reject(error); 1228 } else { 1229 resolve(data); 1230 } 1231 }); 1232 } catch (error) { 1233 throwObject.isThrow = true; 1234 throw(error as Error); 1235 } 1236 }); 1237} 1238 1239async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1240 console.info(`enter callback generateKeyItem`); 1241 let throwObject :throwObject = {isThrow: false}; 1242 try { 1243 await generateKeyItem(keyAlias, huksOptions, throwObject) 1244 .then((data) => { 1245 console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); 1246 }) 1247 .catch((error : BusinessError) => { 1248 if (throwObject.isThrow) { 1249 throw(error as Error); 1250 } else { 1251 console.error(`callback: generateKeyItem failed`); 1252 } 1253 }); 1254 } catch (error) { 1255 console.error(`callback: generateKeyItem input arg invalid`); 1256 } 1257} 1258 1259function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1260 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 1261 try { 1262 huks.initSession(keyAlias, huksOptions, (error, data) => { 1263 if (error) { 1264 reject(error); 1265 } else { 1266 resolve(data); 1267 } 1268 }); 1269 } catch (error) { 1270 throwObject.isThrow = true; 1271 throw(error as Error); 1272 } 1273 }); 1274} 1275 1276async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1277 console.info(`enter callback doInit`); 1278 let throwObject:throwObject = {isThrow: false}; 1279 try { 1280 await initSession(keyAlias, huksOptions, throwObject) 1281 .then ((data) => { 1282 console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); 1283 handle = data.handle; 1284 }) 1285 .catch((error : BusinessError) => { 1286 if (throwObject.isThrow) { 1287 throw(error as Error); 1288 } else { 1289 console.error(`callback: doInit failed`); 1290 } 1291 }); 1292 } catch (error) { 1293 console.error(`callback: doInit input arg invalid`); 1294 } 1295} 1296 1297function updateSession(handle:number, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1298 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 1299 try { 1300 huks.updateSession(handle, huksOptions, (error, data) => { 1301 if (error) { 1302 reject(error); 1303 } else { 1304 resolve(data); 1305 } 1306 }); 1307 } catch (error) { 1308 throwObject.isThrow = true; 1309 throw(error as Error); 1310 } 1311 }); 1312} 1313 1314async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { 1315 console.info(`enter callback doUpdate`); 1316 let throwObject:throwObject = {isThrow: false}; 1317 try { 1318 await updateSession(handle, huksOptions, throwObject) 1319 .then ((data) => { 1320 console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); 1321 }) 1322 .catch((error : BusinessError) => { 1323 if (throwObject.isThrow) { 1324 throw(error as Error); 1325 } else { 1326 console.error(`callback: doUpdate failed`); 1327 } 1328 }); 1329 } catch (error) { 1330 console.error(`callback: doUpdate input arg invalid`); 1331 } 1332} 1333 1334function finishSession(handle:number, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1335 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 1336 try { 1337 huks.finishSession(handle, huksOptions, (error, data) =>{ 1338 if (error) { 1339 reject(error); 1340 } else { 1341 resolve(data); 1342 } 1343 }); 1344 } catch (error) { 1345 throwObject.isThrow = true; 1346 throw(error as Error); 1347 } 1348 }); 1349} 1350 1351async function publicFinishFunc(handle:number, huksOptions:huks.HuksOptions) { 1352 console.info(`enter callback doFinish`); 1353 let throwObject:throwObject = {isThrow: false}; 1354 try { 1355 await finishSession(handle, huksOptions, throwObject) 1356 .then ((data) => { 1357 finishOutData = data.outData as Uint8Array; 1358 console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); 1359 }) 1360 .catch((error : BusinessError) => { 1361 if (throwObject.isThrow) { 1362 throw(error as Error); 1363 } else { 1364 console.error(`callback: doFinish failed`); 1365 } 1366 }); 1367 } catch (error) { 1368 console.error(`callback: doFinish input arg invalid`); 1369 } 1370} 1371 1372function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1373 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 1374 try { 1375 huks.exportKeyItem(keyAlias, huksOptions, (error, data) => { 1376 if (error) { 1377 reject(error); 1378 } else { 1379 resolve(data); 1380 } 1381 }); 1382 } catch (error) { 1383 throwObject.isThrow = true; 1384 throw(error as Error); 1385 } 1386 }); 1387} 1388 1389async function publicExportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1390 console.info(`enter callback export`); 1391 let throwObject:throwObject = {isThrow: false}; 1392 try { 1393 await exportKeyItem(keyAlias, huksOptions, throwObject) 1394 .then ((data) => { 1395 console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); 1396 exportKey = data.outData as Uint8Array; 1397 }) 1398 .catch((error : BusinessError) => { 1399 if (throwObject.isThrow) { 1400 throw(error as Error); 1401 } else { 1402 console.error(`callback: exportKeyItem failed`); 1403 } 1404 }); 1405 } catch (error) { 1406 console.error(`callback: exportKeyItem input arg invalid`); 1407 } 1408} 1409 1410function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1411 return new Promise<void>((resolve, reject) => { 1412 try { 1413 huks.deleteKeyItem(keyAlias, huksOptions, (error, data) => { 1414 if (error) { 1415 reject(error); 1416 } else { 1417 resolve(data); 1418 } 1419 }); 1420 } catch (error) { 1421 throwObject.isThrow = true; 1422 throw(error as Error); 1423 } 1424 }); 1425} 1426 1427async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1428 console.info(`enter callback deleteKeyItem`); 1429 let throwObject : throwObject = {isThrow: false}; 1430 try { 1431 await deleteKeyItem(keyAlias, huksOptions, throwObject) 1432 .then ((data) => { 1433 console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); 1434 }) 1435 .catch((error :BusinessError) => { 1436 if (throwObject.isThrow) { 1437 throw(error as Error); 1438 } else { 1439 console.error(`callback: deleteKeyItem failed`); 1440 } 1441 }); 1442 } catch (error) { 1443 console.error(`callback: deletKeeyItem input arg invalid`); 1444 } 1445} 1446 1447async function testAgree() { 1448 /* 1. Generate two keys and export them. */ 1449 await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions); 1450 await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions); 1451 1452 await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions); 1453 exportKeyFrist = exportKey; 1454 await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions); 1455 exportKeySecond = exportKey; 1456 1457 /* Perform key agreement for the first. */ 1458 await publicInitFunc(srcKeyAliasFirst, HuksOptions); 1459 HuksOptions.inData = exportKeySecond; 1460 await publicUpdateFunc(handle, HuksOptions); 1461 await publicFinishFunc(handle, finishOptionsFrist); 1462 1463 /* Perform key agreement for the second key. */ 1464 await publicInitFunc(srcKeyAliasSecond, HuksOptions); 1465 HuksOptions.inData = exportKeyFrist; 1466 await publicUpdateFunc(handle, HuksOptions); 1467 await publicFinishFunc(handle, finishOptionsSecond); 1468 1469 await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions); 1470 await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions); 1471} 1472``` 1473 1474### Key Derivation 1475 1476You are advised to pass in [HuksKeyStorageType](../reference/apis/js-apis-huks.md#hukskeystoragetype) to specify the storage type in key derivation. From API version 10, only **HUKS_STORAGE_ONLY_USED_IN_HUKS** or **HUKS_STORAGE_KEY_EXPORT_ALLOWED** can be used. If **HuksKeyStorageType** is not passed in, the key can be stored or exported by default, which poses security risks. 1477 1478```ts 1479/* 1480 * The following uses an HKDF256 key and promise-based APIs as an example. 1481 */ 1482import huks from '@ohos.security.huks'; 1483import { BusinessError } from '@ohos.base'; 1484 1485/* 1486 * Set the key alias and encapsulate the key properties. 1487 */ 1488let srcKeyAlias = "hkdf_Key"; 1489let deriveHkdfInData = "deriveHkdfTestIndata"; 1490let handle:number; 1491let finishOutData:Uint8Array; 1492let HuksKeyDeriveKeySize = 32; 1493 1494/* Configure the parameter set used for generating the key. */ 1495let properties:Array<huks.HuksParam> = new Array(); 1496properties[0] = { 1497 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1498 value: huks.HuksKeyAlg.HUKS_ALG_AES, 1499} 1500properties[1] = { 1501 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1502 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE, 1503} 1504properties[2] = { 1505 tag: huks.HuksTag.HUKS_TAG_DIGEST, 1506 value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256, 1507} 1508properties[3] = { 1509 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1510 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128, 1511} 1512properties[4] = { 1513 tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, 1514 value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS, 1515} 1516let huksOptions:huks.HuksOptions = { 1517 properties: properties, 1518 inData: new Uint8Array(new Array()) 1519} 1520 1521/* Configure the parameter set used for init(). */ 1522let initProperties:Array<huks.HuksParam> = new Array(); 1523initProperties[0] = { 1524 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1525 value: huks.HuksKeyAlg.HUKS_ALG_HKDF, 1526} 1527initProperties[1] = { 1528 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1529 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE, 1530} 1531initProperties[2] = { 1532 tag: huks.HuksTag.HUKS_TAG_DIGEST, 1533 value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256, 1534} 1535initProperties[3] = { 1536 tag: huks.HuksTag.HUKS_TAG_DERIVE_KEY_SIZE, 1537 value: HuksKeyDeriveKeySize, 1538} 1539let initOptions:huks.HuksOptions = { 1540 properties: initProperties, 1541 inData: new Uint8Array(new Array()) 1542} 1543 1544/* Configure the parameter set used for finish(). */ 1545let finishProperties:Array<huks.HuksParam> = new Array(); 1546finishProperties[0] = { 1547 tag: huks.HuksTag.HUKS_TAG_DERIVED_AGREED_KEY_STORAGE_FLAG, 1548 value: huks.HuksKeyStorageType.HUKS_STORAGE_ONLY_USED_IN_HUKS, 1549} 1550finishProperties[1] = { 1551 tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, 1552 value: true, 1553} 1554finishProperties[2] = { 1555 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1556 value: huks.HuksKeyAlg.HUKS_ALG_AES, 1557} 1558finishProperties[3] = { 1559 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1560 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, 1561} 1562finishProperties[4] = { 1563 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1564 value: 1565 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | 1566 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 1567} 1568finishProperties[5] = { 1569 tag: huks.HuksTag.HUKS_TAG_DIGEST, 1570 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, 1571} 1572finishProperties[6] = { 1573 tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, 1574 value: StringToUint8Array(srcKeyAlias), 1575} 1576finishProperties[7] = { 1577 tag: huks.HuksTag.HUKS_TAG_PADDING, 1578 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 1579} 1580finishProperties[8] = { 1581 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 1582 value: huks.HuksCipherMode.HUKS_MODE_ECB, 1583} 1584let finishOptions:huks.HuksOptions = { 1585 properties: finishProperties, 1586 inData: new Uint8Array(new Array()) 1587} 1588 1589function StringToUint8Array(str:String) { 1590 let arr:number[]=new Array(); 1591 for (let i = 0, j = str.length; i < j; ++i) { 1592 arr.push(str.charCodeAt(i)); 1593 } 1594 return new Uint8Array(arr); 1595} 1596 1597class throwObject{ 1598 isThrow=false; 1599} 1600 1601function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1602 return new Promise<void>((resolve, reject) => { 1603 try { 1604 huks.generateKeyItem(keyAlias, huksOptions, (error, data)=> { 1605 if (error) { 1606 reject(error); 1607 } else { 1608 resolve(data); 1609 } 1610 }); 1611 } catch (error) { 1612 throwObject.isThrow = true; 1613 throw(error as Error); 1614 } 1615 }); 1616} 1617 1618async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1619 console.info(`enter callback generateKeyItem`); 1620 let throwObject:throwObject = {isThrow: false}; 1621 try { 1622 await generateKeyItem(keyAlias, huksOptions, throwObject) 1623 .then((data) => { 1624 console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); 1625 }) 1626 .catch((error:BusinessError) => { 1627 if (throwObject.isThrow) { 1628 throw(error as Error); 1629 } else { 1630 console.error(`callback: generateKeyItem failed`); 1631 } 1632 }); 1633 } catch (error) { 1634 console.error(`callback: generateKeyItem input arg invalid`); 1635 } 1636} 1637 1638function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1639 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 1640 try { 1641 huks.initSession(keyAlias, huksOptions, (error, data)=> { 1642 if (error) { 1643 reject(error); 1644 } else { 1645 resolve(data); 1646 } 1647 }); 1648 } catch (error) { 1649 throwObject.isThrow = true; 1650 throw(error as Error); 1651 } 1652 }); 1653} 1654 1655async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1656 console.info(`enter callback doInit`); 1657 let throwObject:throwObject = {isThrow: false}; 1658 try { 1659 await initSession(keyAlias, huksOptions, throwObject) 1660 .then ((data) => { 1661 console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); 1662 handle = data.handle; 1663 }) 1664 .catch((error:BusinessError) => { 1665 if (throwObject.isThrow) { 1666 throw(error as Error); 1667 } else { 1668 console.error(`callback: doInit failed`); 1669 } 1670 }); 1671 } catch (error) { 1672 console.error(`callback: doInit input arg invalid`); 1673 } 1674} 1675 1676function updateSession(handle:number, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1677 return new Promise<huks.HuksOptions>((resolve, reject) => { 1678 try { 1679 huks.updateSession(handle, huksOptions, (error, data)=> { 1680 if (error) { 1681 reject(error); 1682 } else { 1683 resolve(data); 1684 } 1685 }); 1686 } catch (error) { 1687 throwObject.isThrow = true; 1688 throw(error as Error); 1689 } 1690 }); 1691} 1692 1693async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { 1694 console.info(`enter callback doUpdate`); 1695 let throwObject:throwObject = {isThrow: false}; 1696 try { 1697 await updateSession(handle, huksOptions, throwObject) 1698 .then ((data) => { 1699 console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); 1700 }) 1701 .catch((error:BusinessError) => { 1702 if (throwObject.isThrow) { 1703 throw(error as Error); 1704 } else { 1705 console.error(`callback: doUpdate failed`); 1706 } 1707 }); 1708 } catch (error) { 1709 console.error(`callback: doUpdate input arg invalid`); 1710 } 1711} 1712 1713function finishSession(handle:number, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1714 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 1715 try { 1716 huks.finishSession(handle, huksOptions, (error, data)=> { 1717 if (error) { 1718 reject(error); 1719 } else { 1720 resolve(data); 1721 } 1722 }); 1723 } catch (error) { 1724 throwObject.isThrow = true; 1725 throw(error as Error); 1726 } 1727 }); 1728} 1729 1730async function publicFinishFunc(handle:number, huksOptions:huks.HuksOptions) { 1731 console.info(`enter callback doFinish`); 1732 let throwObject:throwObject = {isThrow: false}; 1733 try { 1734 await finishSession(handle, huksOptions, throwObject) 1735 .then ((data) => { 1736 finishOutData = data.outData as Uint8Array; 1737 console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); 1738 }) 1739 .catch((error:BusinessError) => { 1740 if (throwObject.isThrow) { 1741 throw(error as Error); 1742 } else { 1743 console.error(`callback: doFinish failed`); 1744 } 1745 }); 1746 } catch (error) { 1747 console.error(`callback: doFinish input arg invalid`); 1748 } 1749} 1750 1751function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1752 return new Promise<void>((resolve, reject) => { 1753 try { 1754 huks.deleteKeyItem(keyAlias, huksOptions, (error, data)=> { 1755 if (error) { 1756 reject(error); 1757 } else { 1758 resolve(data); 1759 } 1760 }); 1761 } catch (error) { 1762 throwObject.isThrow = true; 1763 throw(error as Error); 1764 } 1765 }); 1766} 1767 1768async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1769 console.info(`enter callback deleteKeyItem`); 1770 let throwObject:throwObject = {isThrow: false}; 1771 try { 1772 await deleteKeyItem(keyAlias, huksOptions, throwObject) 1773 .then ((data) => { 1774 console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); 1775 }) 1776 .catch((error:BusinessError) => { 1777 if (throwObject.isThrow) { 1778 throw(error as Error); 1779 } else { 1780 console.error(`callback: deleteKeyItem failed`); 1781 } 1782 }); 1783 } catch (error) { 1784 console.error(`callback: deletKeeyItem input arg invalid`); 1785 } 1786} 1787 1788async function testDerive() { 1789 /* Generate a key. */ 1790 await publicGenKeyFunc(srcKeyAlias, huksOptions); 1791 1792 /* Derive a key. */ 1793 await publicInitFunc(srcKeyAlias, initOptions); 1794 1795 initOptions.inData = StringToUint8Array(deriveHkdfInData); 1796 await publicUpdateFunc(handle, initOptions); 1797 await publicFinishFunc(handle, finishOptions); 1798 1799 await publicDeleteKeyFunc(srcKeyAlias, huksOptions); 1800} 1801``` 1802 1803## Key Access Control 1804 1805The HUKS provides comprehensive key access control to prevent unauthorized access. 1806 1807Services can access only their own keys, that is, the keys generated or imported through HUKS. 1808In addition, the HUKS supports user identity authentication for security-sensitive services. Users can use the service keys only after the authentication (PIN or biometric authentication) is successful. 1809The HUKS also restricts the key usage. For example, the AES keys can only be used for encryption and decryption, and the RSA keys can only be used for signing and signature verification. 1810 1811### User Identity Authentication 1812 1813During the key generation or import process, user identity authentication can be enabled to allow the use of the key only after the authentication is successful. You can specify a subset of credentials (lock screen password, fingerprint, and face) for user identity authentication. After a key is generated or imported, unauthorized key access can be prevented even if the application process is attacked. Key access control applies to security-sensitive scenarios, such as password-free login, password-free payment, and automatic password filling. 1814 1815In addition to user identity authentication, the HUKS provides the following modes for automatically invalidating a key: 1816 1817- Invalidate the key when the screen lock password is cleared.<br>This mode takes effect only when a screen lock password has been set. If the screen lock password is cleared, the key becomes invalid permanently. The key will not be invalidated if the screen lock password is modified. This mode applies to user-related data protection or access based on screen lock passwords. 1818- Invalidate the key when new biometric enrollments are added.<br>This mode takes effect only when at least one biometric feature (such as fingerprint) has been enrolled. The key becomes invalid permanently once a new biometric feature is enrolled. The key will not be invalidated if the biometric feature is deleted. This mode applies to scenarios, such as password-free login or payment. 1819 1820To ensure the validity of the user authentication result, the HUKS supports challenge verification. Before user identity authentication, obtain the challenge (in [HuksSessionHandle](../reference/apis/js-apis-huks.md#hukssessionhandle9) returned by [huks.initSession()](../reference/apis/js-apis-huks.md#huksinitsession9)) from the HUKS and pass in the challenge in **userIAM_userAuth.getAuthInstance**. The challenge of the authentication token is then verified during key operations. 1821 1822**How to Develop** 1823 1824If secondary user identity authentication is enabled for a key, initialize the key session and obtain the challenge. Then, pass the challenge to **userIAM_userAuth.getAuthInstance()** for user identity authentication. After the authentication is successful, an authentication token is obtained. The authentication token can be used to perform key operations. 1825 1826 1827 1828**Available APIs** 1829 1830When a key is generated or imported, [HuksUserAuthType](../reference/apis/js-apis-huks.md#huksuserauthtype9), [HuksAuthAccessType](../reference/apis/js-apis-huks.md#huksauthaccesstype9), and [HuksChallengeType](../reference/apis/js-apis-huks.md#hukschallengetype9) in the key properties are mandatory. 1831 1832 **Table 3** User authentication types 1833| Name | Value | Description | 1834| ------------------------------- |---|------------------------ | 1835| HUKS_USER_AUTH_TYPE_FINGERPRINT |0x0001 | Fingerprint authentication, which can be enabled with facial authentication and PIN authentication at the same time. | 1836| HUKS_USER_AUTH_TYPE_FACE |0x0002 | Facial authentication, whch can be enabled with fingerprint authentication and PIN authentication at the same time.| 1837| HUKS_USER_AUTH_TYPE_PIN |0x0004 | PIN authentication, which can be enabled with fingerprint authentication and facial authenticationat the same time. | 1838 1839**Table 4** Secure access types 1840| Name | Value | Description | 1841| --------------------------------------- | ---- | ------------------------------------------------ | 1842| HUKS_AUTH_ACCESS_INVALID_CLEAR_PASSWORD | 1 | Invalidates the key after the screen lock password is cleared. | 1843| HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL | 2 | Invalidates the key after a biometric enrollment is added. The user authentication types must include the biometric authentication.| 1844 1845**Table 5** Challenge types 1846| Name | Value | Description | 1847| ------------------------------- | ---- | ------------------------------ | 1848| HUKS_CHALLENGE_TYPE_NORMAL | 0 | Normal challenge, which requires an independent user authentication for each use of the key.| 1849| HUKS_CHALLENGE_TYPE_CUSTOM | 1 | Custom challenge, which supports only one user authentication for multiple keys.| 1850| HUKS_CHALLENGE_TYPE_NONE | 2 | No challenge is required during user authentication.| 1851 1852 > **NOTICE** 1853 > 1854 > If the challenge type is **HUKS_CHALLENGE_TYPE_NONE**, no challenge is required. However, the key can be accessed within a specified time period (set by **HUKS_TAG_AUTH_TIMEOUT**) after a successful authentication. The maximum value of **HUKS_TAG_AUTH_TIMEOUT** is 60 seconds. 1855 1856To use a key, initialize the key session, and determine whether a challenge is required based on the challenge type specified when the key is generated or imported. 1857 1858 **Table 6** APIs for using a key 1859| API | Description | 1860| -------------------------------------- | ----------------------------| 1861|initSession(keyAlias: string, options: HuksOptions, callback: AsyncCallback\<HuksSessionHandle>) : void| Initializes the key session and obtains the challenge.| 1862|updateSession(handle: number, options: HuksOptions, token: Uint8Array, callback: AsyncCallback\<HuksReturnResult>) : void| Operates data by segment and passes the authentication token.| 1863|finishSession(handle: number, options: HuksOptions, token: Uint8Array, callback: AsyncCallback\<HuksReturnResult>) : void| Finishes the key session.| 1864 1865**How to Develop** 1866 18671. Generate a key and specify user authentication properties. 1868 1869 ```ts 1870 import huks from '@ohos.security.huks'; 1871 import { BusinessError } from '@ohos.base'; 1872 1873 /* 1874 * Set the key alias and encapsulate the key properties. 1875 */ 1876 let keyAlias = 'dh_key_fingerprint_access'; 1877 let properties : Array<huks.HuksParam> = new Array(); 1878 properties[0] = { 1879 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1880 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 1881 } 1882 properties[1] = { 1883 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1884 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 1885 } 1886 properties[2] = { 1887 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1888 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 1889 } 1890 properties[3] = { 1891 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 1892 value: huks.HuksCipherMode.HUKS_MODE_CBC, 1893 } 1894 properties[4] = { 1895 tag: huks.HuksTag.HUKS_TAG_PADDING, 1896 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 1897 } 1898 // Enable fingerprint authentication. 1899 properties[5] = { 1900 tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, 1901 value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT 1902 } 1903 // Set the key expiration type. Invalidate the key when a new biometric feature (fingerprint) is enrolled. 1904 properties[6] = { 1905 tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, 1906 value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL 1907 } 1908 // Use the default challenge type. 1909 properties[7] = { 1910 tag: huks.HuksTag.HUKS_TAG_CHALLENGE_TYPE, 1911 value: huks.HuksChallengeType.HUKS_CHALLENGE_TYPE_NORMAL 1912 } 1913 let huksOptions : huks.HuksOptions = { 1914 properties: properties, 1915 inData: new Uint8Array(new Array()) 1916 } 1917 1918 /* 1919 * Generate a key. 1920 */ 1921 class throwObject { 1922 isThrow:boolean = false 1923 } 1924 function generateKeyItem(keyAlias : string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 1925 return new Promise<void>((resolve, reject) => { 1926 try { 1927 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 1928 if (error) { 1929 reject(error); 1930 } else { 1931 resolve(data); 1932 } 1933 }); 1934 } catch (error) { 1935 throwObject.isThrow = true; 1936 throw(error as Error); 1937 } 1938 }); 1939 } 1940 1941 async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 1942 console.info(`enter callback generateKeyItem`); 1943 let throwObject : throwObject = {isThrow: false}; 1944 try { 1945 await generateKeyItem(keyAlias, huksOptions, throwObject) 1946 .then((data) => { 1947 console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); 1948 }) 1949 .catch((error : BusinessError) => { 1950 if (throwObject.isThrow) { 1951 throw(error as Error); 1952 } else { 1953 console.error(`callback: generateKeyItem failed`); 1954 } 1955 }); 1956 } catch (error) { 1957 console.error(`callback: generateKeyItem input arg invalid`); 1958 } 1959 } 1960 1961 async function TestGenKeyForFingerprintAccessControl() { 1962 await publicGenKeyFunc(keyAlias, huksOptions); 1963 } 1964 ``` 1965 19662. Initialize the key session to obtain a challenge, and initiate fingerprint authentication to obtain an authentication token. 1967 1968 ```ts 1969 import huks from '@ohos.security.huks'; 1970 import userIAM_userAuth from '@ohos.userIAM.userAuth'; 1971 import { BusinessError } from '@ohos.base'; 1972 1973 /* 1974 * Set the key alias and encapsulate the key properties. 1975 */ 1976 let srcKeyAlias = 'sm4_key_fingerprint_access'; 1977 let handle : number; 1978 let challenge : Uint8Array; 1979 let fingerAuthToken : Uint8Array; 1980 let authType = userIAM_userAuth.UserAuthType.FINGERPRINT; 1981 let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1; 1982 1983 /* Configure the key generation parameter set and key encryption parameter set. */ 1984 let properties : Array<huks.HuksParam> = new Array(); 1985 properties[0] = { 1986 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 1987 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 1988 } 1989 properties[1] = { 1990 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 1991 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 1992 } 1993 properties[2] = { 1994 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 1995 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 1996 } 1997 properties[3] = { 1998 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 1999 value: huks.HuksCipherMode.HUKS_MODE_CBC, 2000 } 2001 properties[4] = { 2002 tag: huks.HuksTag.HUKS_TAG_PADDING, 2003 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 2004 } 2005 let huksOptions : huks.HuksOptions = { 2006 properties: properties, 2007 inData: new Uint8Array(new Array()) 2008 } 2009 2010 class throwObject { 2011 isThrow:boolean=false 2012 } 2013 2014 function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject:throwObject) { 2015 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 2016 try { 2017 huks.initSession(keyAlias, huksOptions, (error, data) =>{ 2018 if (error) { 2019 reject(error); 2020 } else { 2021 resolve(data); 2022 } 2023 }); 2024 } catch (error) { 2025 throwObject.isThrow = true; 2026 throw(error as Error); 2027 } 2028 }); 2029 } 2030 2031 async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { 2032 console.info(`enter callback doInit`); 2033 let throwObject : throwObject = {isThrow: false}; 2034 try { 2035 await initSession(keyAlias, huksOptions, throwObject) 2036 .then ((data) => { 2037 console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); 2038 handle = data.handle; 2039 challenge = data.challenge as Uint8Array; 2040 }) 2041 .catch((error : BusinessError) => { 2042 if (throwObject.isThrow) { 2043 throw(error as Error); 2044 } else { 2045 console.error(`callback: doInit failed`); 2046 } 2047 }); 2048 } catch (error) { 2049 console.error(`callback: doInit input arg invalid`); 2050 } 2051 } 2052 2053 function userIAMAuthFinger(huksChallenge:Uint8Array) { 2054 // Obtain an authentication object. 2055 let auth : userIAM_userAuth.AuthInstance; 2056 try { 2057 auth = userIAM_userAuth.getAuthInstance(huksChallenge, authType, authTrustLevel); 2058 console.log("get auth instance success"); 2059 } catch (error) { 2060 console.log("get auth instance failed" + error); 2061 return; 2062 } 2063 2064 // Subscribe to the authentication result. 2065 try { 2066 auth.on("result", { 2067 callback: (result:userIAM_userAuth.AuthResultInfo) => { 2068 /* The authentication is successful, and the authentication token is obtained. */ 2069 fingerAuthToken = result.token as Uint8Array; 2070 } 2071 }); 2072 console.log("subscribe authentication event success"); 2073 } catch (error) { 2074 console.log("subscribe authentication event failed " + error); 2075 } 2076 2077 // Start user authentication. 2078 try { 2079 auth.start(); 2080 console.info("authV9 start auth success"); 2081 } catch (error) { 2082 console.info("authV9 start auth failed, error = " + error); 2083 } 2084 } 2085 2086 async function testInitAndAuthFinger() { 2087 /* Initialize the key session to obtain a challenge. */ 2088 await publicInitFunc(srcKeyAlias, huksOptions); 2089 /* Invoke userIAM to perform user identity authentication. */ 2090 userIAMAuthFinger(challenge); 2091 } 2092 ``` 2093 20943. Pass in the authentication token to perform data operations. 2095 2096 ```ts 2097 /* 2098 * The following uses an SM4 128-bit key and callback-based APIs as an example. 2099 */ 2100 import huks from '@ohos.security.huks'; 2101 import { BusinessError } from '@ohos.base'; 2102 2103 /* 2104 * Set the key alias and encapsulate the key properties. 2105 */ 2106 let srcKeyAlias = 'sm4_key_fingerprint_access'; 2107 let IV = '1234567890123456'; 2108 let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; 2109 let handle: number; 2110 let fingerAuthToken: Uint8Array; 2111 let finishOutData: Uint8Array; 2112 2113 class throwObject { 2114 isThrow: boolean = false; 2115 } 2116 2117 /* Configure the key generation parameter set and key encryption parameter set. */ 2118 class propertyEncryptType { 2119 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 2120 value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksKeyPadding | huks.HuksCipherMode 2121 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_SM4; 2122 } 2123 2124 let propertiesEncrypt: propertyEncryptType[] = [ 2125 { 2126 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 2127 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 2128 }, 2129 { 2130 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 2131 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, 2132 }, 2133 { 2134 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 2135 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 2136 }, 2137 { 2138 tag: huks.HuksTag.HUKS_TAG_PADDING, 2139 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 2140 }, 2141 { 2142 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 2143 value: huks.HuksCipherMode.HUKS_MODE_CBC, 2144 }, 2145 { 2146 tag: huks.HuksTag.HUKS_TAG_IV, 2147 value: StringToUint8Array(IV), 2148 } 2149 ] 2150 2151 let encryptOptions: huks.HuksOptions = { 2152 properties: propertiesEncrypt, 2153 inData: new Uint8Array(new Array()) 2154 } 2155 2156 function StringToUint8Array(str: string) { 2157 let arr: number[] = []; 2158 for (let i = 0, j = str.length; i < j; ++i) { 2159 arr.push(str.charCodeAt(i)); 2160 } 2161 return new Uint8Array(arr); 2162 } 2163 2164 function updateSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) { 2165 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 2166 try { 2167 huks.updateSession(handle, huksOptions, token, (error, data) => { 2168 if (error) { 2169 reject(error); 2170 } else { 2171 resolve(data); 2172 } 2173 }); 2174 } catch (error) { 2175 throwObject.isThrow = true; 2176 throw(error as Error); 2177 } 2178 }); 2179 } 2180 2181 async function publicUpdateFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) { 2182 console.info(`enter callback doUpdate`); 2183 let throwObject: throwObject = {isThrow: false}; 2184 try { 2185 await updateSession(handle, huksOptions, token, throwObject) 2186 .then ((data) => { 2187 console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); 2188 }) 2189 .catch((error: BusinessError) => { 2190 if (throwObject.isThrow) { 2191 throw(error as Error); 2192 } else { 2193 console.error(`callback: doUpdate failed`); 2194 } 2195 }); 2196 } catch (error) { 2197 console.error(`callback: doUpdate input arg invalid`); 2198 } 2199 } 2200 2201 function finishSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) { 2202 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 2203 try { 2204 huks.finishSession(handle, huksOptions, token, (error, data) => { 2205 if (error) { 2206 reject(error); 2207 } else { 2208 resolve(data); 2209 } 2210 }); 2211 } catch (error) { 2212 throwObject.isThrow = true; 2213 throw(error as Error); 2214 } 2215 }); 2216 } 2217 2218 async function publicFinishFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) { 2219 console.info(`enter callback doFinish`); 2220 let throwObject: throwObject = {isThrow: false}; 2221 try { 2222 await finishSession(handle, huksOptions, token, throwObject) 2223 .then ((data) => { 2224 finishOutData = data.outData as Uint8Array; 2225 console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); 2226 }) 2227 .catch((error: BusinessError) => { 2228 if (throwObject.isThrow) { 2229 throw(error as Error); 2230 } else { 2231 console.error(`callback: doFinish failed`); 2232 } 2233 }); 2234 } catch (error) { 2235 console.error(`callback: doFinish input arg invalid`); 2236 } 2237 } 2238 2239 async function testSm4Cipher() { 2240 encryptOptions.inData = StringToUint8Array(cipherInData); 2241 /* Pass in the authentication token. */ 2242 await publicUpdateFunc(handle, fingerAuthToken, encryptOptions); 2243 encryptOptions.inData = new Uint8Array(new Array()); 2244 /* Pass in the authentication token. */ 2245 await publicFinishFunc(handle, fingerAuthToken, encryptOptions); 2246 if (finishOutData === StringToUint8Array(cipherInData)) { 2247 console.info('test finish encrypt err '); 2248 } else { 2249 console.info('test finish encrypt success'); 2250 } 2251 } 2252 ``` 2253 2254### Refined User Identity Authentication 2255 2256As an extension to [Key Access Control](#key-access-control), the refined access control allows secondary user identity authentication (biometric authentication and lock screen password) to be performed for key access in one or more scenarios, such as encryption, decryption, signing, signature verification, key agreement, and key derivation. For example, a service needs to use a HUKS key to encrypt the account password information. In this scenario, identity authentication is not required in encryption but required in decryption. To achieve this purpose, you can use the refined user identity authentication feature provided by the HUKS. 2257 2258**How to Develop** 2259 22601. Specify [HUKS_TAG_KEY_AUTH_PURPOSE](../reference/apis/js-apis-huks.md#hukstag) in key generation to allow refined user identity authentication to be performed when a specific algorithm is used. 22612. The **HUKS_TAG_KEY_AUTH_PURPOSE** does not need to be specified for the key usage process. The development process is the same as that of the user identity authentication process. 2262 2263**Available APIs** 2264 2265You can use the [HUKS_TAG_KEY_AUTH_PURPOSE](../reference/apis/js-apis-huks.md#hukstag) tag to specify the scenarios, for which the refined user identity authentication is performed. The value range of this tag is [HuksKeyAlg](../reference/apis/js-apis-huks.md#hukskeyalg). 2266 2267**Table 7** HUKS_TAG_KEY_AUTH_PURPOSE 2268| Name | Description | 2269| -------------------------------------- | ----------------------------| 2270|HUKS_TAG_KEY_AUTH_PURPOSE| Purpose of the user identity authentication, that is, perform the user identity authentication when a specific algorithm is used.| 2271 2272> **NOTICE** 2273> 2274> - If [**HuksUserAuthType**](../reference/apis/js-apis-huks.md#huksuserauthtype9) is not specified, no user identity authentication is performed by default. In this case, the setting of **HUKS_TAG_KEY_AUTH_PURPOSE** is invalid by default. If **HuksUserAuthType** is specified and **HUKS_TAG_KEY_AUTH_PURPOSE** is not specified, user identity authentication will still be performed by default before the key is used with the algorithm that is specified in the key generation process. 2275> - If the AES or SM4 symmetric algorithm is used for encryption and decryption, only the CBC mode supports refined user identity authentication. 2276 2277**How to Develop** 2278 2279Scenario: When generating keys for encryption and decryption, enable user identity authentication only for decryption. Enable user identity authentication for decryption but not for encryption. 2280 22811. Generate a key, set fingerprint authentication for key access control and related properties, and set **HUKS_TAG_KEY_AUTH_PURPOSE**. 2282 2283 ```ts 2284 import huks from '@ohos.security.huks'; 2285 import { BusinessError } from '@ohos.base'; 2286 2287 /* 2288 * Set the key alias and encapsulate the key properties. 2289 */ 2290 let keyAlias = 'dh_key_fingerprint_access'; 2291 2292 class throwObject { 2293 isThrow: boolean = false; 2294 } 2295 2296 class propertyType { 2297 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 2298 value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksCipherMode | huks.HuksKeyPadding 2299 | huks.HuksUserAuthType | huks.HuksAuthAccessType | huks.HuksChallengeType = huks.HuksKeyAlg.HUKS_ALG_SM4 2300 } 2301 let properties: propertyType[] = [ 2302 { 2303 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 2304 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 2305 }, 2306 { 2307 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 2308 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 2309 }, 2310 { 2311 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 2312 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 2313 }, 2314 { 2315 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 2316 value: huks.HuksCipherMode.HUKS_MODE_CBC, 2317 }, 2318 { 2319 tag: huks.HuksTag.HUKS_TAG_PADDING, 2320 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 2321 }, 2322 { 2323 tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, 2324 value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT 2325 }, 2326 { 2327 tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, 2328 value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL 2329 }, 2330 { 2331 tag: huks.HuksTag.HUKS_TAG_CHALLENGE_TYPE, 2332 value: huks.HuksChallengeType.HUKS_CHALLENGE_TYPE_NORMAL 2333 }, 2334 { 2335 tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_PURPOSE, 2336 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 2337 } 2338 ] 2339 2340 let huksOptions: huks.HuksOptions = { 2341 properties: properties, 2342 inData: new Uint8Array(new Array()) 2343 } 2344 2345 /* 2346 * Generate a key. 2347 */ 2348 async function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 2349 return new Promise<void>((resolve, reject) => { 2350 try { 2351 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 2352 if (error) { 2353 reject(error); 2354 } else { 2355 resolve(data); 2356 } 2357 }); 2358 } catch (error) { 2359 throwObject.isThrow = true; 2360 throw(error as Error); 2361 } 2362 }); 2363 } 2364 2365 async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 2366 console.info(`enter callback generateKeyItem`); 2367 let throwObject: throwObject = {isThrow: false}; 2368 try { 2369 await generateKeyItem(keyAlias, huksOptions, throwObject) 2370 .then((data) => { 2371 console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); 2372 }) 2373 .catch((error: BusinessError) => { 2374 if (throwObject.isThrow) { 2375 throw(error as Error); 2376 } else { 2377 console.error(`callback: generateKeyItem failed`); 2378 } 2379 }); 2380 } catch (error) { 2381 console.error(`callback: generateKeyItem input arg invalid`); 2382 } 2383 } 2384 2385 async function TestGenKeyForFingerprintAccessControl() { 2386 await publicGenKeyFunc(keyAlias, huksOptions); 2387 } 2388 ``` 2389 23902. Disable user identity authentication when the key is used for encryption. 2391 2392 ```ts 2393 import huks from '@ohos.security.huks'; 2394 import { BusinessError } from '@ohos.base'; 2395 2396 class HuksProperties { 2397 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 2398 value: huks.HuksKeyAlg | huks.HuksKeySize | huks.HuksKeyPurpose | huks.HuksKeyPadding | huks.HuksCipherMode 2399 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_ECC; 2400 } 2401 2402 /* 2403 * Set the key alias and encapsulate the key properties. 2404 */ 2405 let srcKeyAlias = 'sm4_key_fingerprint_access'; 2406 let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; // Plaintext 2407 let IV = '1234567890123456'; 2408 let handle = 0; 2409 let cipherText: Uint8Array; // Ciphertext data after encryption. 2410 2411 function StringToUint8Array(str: string) { 2412 let arr: number[] = []; 2413 for (let i = 0, j = str.length; i < j; ++i) { 2414 arr.push(str.charCodeAt(i)); 2415 } 2416 return new Uint8Array(arr); 2417 } 2418 2419 /* Configure the key generation parameter set and key encryption parameter set. */ 2420 let propertiesEncrypt: HuksProperties[] = [ 2421 { 2422 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 2423 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 2424 }, 2425 { 2426 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 2427 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, 2428 }, 2429 { 2430 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 2431 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 2432 }, 2433 { 2434 tag: huks.HuksTag.HUKS_TAG_PADDING, 2435 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 2436 }, 2437 { 2438 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 2439 value: huks.HuksCipherMode.HUKS_MODE_CBC, 2440 }, 2441 { 2442 tag: huks.HuksTag.HUKS_TAG_IV, 2443 value: StringToUint8Array(IV), 2444 } 2445 ]; 2446 let encryptOptions: huks.HuksOptions = { 2447 properties: propertiesEncrypt, 2448 inData: new Uint8Array(new Array()) 2449 } 2450 class throwObject1{ 2451 isThrow: boolean = false; 2452 } 2453 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject1) { 2454 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 2455 try { 2456 huks.initSession(keyAlias, huksOptions, (error, data) => { 2457 if (error) { 2458 reject(error); 2459 } else { 2460 resolve(data); 2461 } 2462 }); 2463 } catch (error) { 2464 throwObject.isThrow = true; 2465 throw (error as Error); 2466 } 2467 }); 2468 } 2469 2470 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 2471 console.info(`enter callback doInit`); 2472 let throwObject: throwObject1 = { isThrow: false }; 2473 try { 2474 await initSession(keyAlias, huksOptions, throwObject) 2475 .then((data) => { 2476 console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); 2477 handle = data.handle as number; 2478 }) 2479 .catch((error: BusinessError) => { 2480 if (throwObject.isThrow) { 2481 throw (error as Error); 2482 } else { 2483 console.error(`callback: doInit failed`); 2484 } 2485 }); 2486 } catch (error) { 2487 console.error(`callback: doInit input arg invalid`); 2488 } 2489 } 2490 2491 function finishSession(handle: number, huksOptions: huks.HuksOptions, throwObject: throwObject1) { 2492 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 2493 try { 2494 huks.finishSession(handle, huksOptions, (error, data) => { 2495 if (error) { 2496 reject(error); 2497 } else { 2498 resolve(data); 2499 } 2500 }); 2501 } catch (error) { 2502 throwObject.isThrow = true; 2503 throw (error as Error); 2504 } 2505 }); 2506 } 2507 2508 async function publicFinishFunc(handle: number, huksOptions: huks.HuksOptions) { 2509 console.info(`enter callback doFinish`); 2510 let throwObject: throwObject1 = { isThrow: false }; 2511 try { 2512 await finishSession(handle, huksOptions, throwObject) 2513 .then((data) => { 2514 cipherText = data.outData as Uint8Array; 2515 console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); 2516 }) 2517 .catch((error: BusinessError) => { 2518 if (throwObject.isThrow) { 2519 throw (error as Error); 2520 } else { 2521 console.error(`callback: doFinish failed`); 2522 } 2523 }); 2524 } catch (error) { 2525 console.error(`callback: doFinish input arg invalid`); 2526 } 2527 } 2528 2529 async function testSm4Cipher() { 2530 /* Initialize the key session to obtain a challenge. */ 2531 await publicInitFunc(srcKeyAlias, encryptOptions); 2532 2533 /** Encryption */ 2534 encryptOptions.inData = StringToUint8Array(cipherInData); 2535 await publicFinishFunc(handle, encryptOptions); 2536 } 2537 ``` 2538 25393. Enable user identity authentication when the key is used for decryption. 2540 2541 ```ts 2542 import huks from '@ohos.security.huks'; 2543 import userIAM_userAuth from '@ohos.userIAM.userAuth'; 2544 import { BusinessError } from '@ohos.base'; 2545 2546 /* 2547 * Set the key alias and encapsulate the key properties. 2548 */ 2549 let srcKeyAlias = 'sm4_key_fingerprint_access'; 2550 let cipherText = 'r56ywtTJUQC6JFJ2VV2kZw=='; // Ciphertext obtained, which may vary in actual situation. 2551 let IV = '1234567890123456'; 2552 let handle: number; 2553 let finishOutData: Uint8Array; // Plaintext data after decryption. 2554 let fingerAuthToken: Uint8Array; 2555 let challenge: Uint8Array; 2556 let authType = userIAM_userAuth.UserAuthType.FINGERPRINT; 2557 let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1; 2558 2559 class throwObject { 2560 isThrow: boolean = false; 2561 } 2562 2563 function StringToUint8Array(str: string) { 2564 let arr: number[] = []; 2565 for (let i = 0, j = str.length; i < j; ++i) { 2566 arr.push(str.charCodeAt(i)); 2567 } 2568 return new Uint8Array(arr); 2569 } 2570 2571 /* Configure the key generation parameter set and key encryption parameter set. */ 2572 class propertyDecryptType { 2573 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM 2574 value: huks.HuksKeyAlg | huks.HuksKeyPurpose | huks.HuksKeySize | huks.HuksKeyPadding | huks.HuksCipherMode 2575 | Uint8Array = huks.HuksKeyAlg.HUKS_ALG_SM4 2576 } 2577 2578 let propertiesDecrypt: propertyDecryptType[] = [ 2579 { 2580 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 2581 value: huks.HuksKeyAlg.HUKS_ALG_SM4, 2582 }, 2583 { 2584 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 2585 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, 2586 }, 2587 { 2588 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 2589 value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, 2590 }, 2591 { 2592 tag: huks.HuksTag.HUKS_TAG_PADDING, 2593 value: huks.HuksKeyPadding.HUKS_PADDING_NONE, 2594 }, 2595 { 2596 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 2597 value: huks.HuksCipherMode.HUKS_MODE_CBC, 2598 }, 2599 { 2600 tag: huks.HuksTag.HUKS_TAG_IV, 2601 value: StringToUint8Array(IV), 2602 } 2603 ] 2604 2605 let decryptOptions: huks.HuksOptions = { 2606 properties: propertiesDecrypt, 2607 inData: new Uint8Array(new Array()) 2608 } 2609 2610 function initSession(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 2611 return new Promise<huks.HuksSessionHandle>((resolve, reject) => { 2612 try { 2613 huks.initSession(keyAlias, huksOptions, (error, data) => { 2614 if (error) { 2615 reject(error); 2616 } else { 2617 resolve(data); 2618 } 2619 }); 2620 } catch (error) { 2621 throwObject.isThrow = true; 2622 throw(error as Error); 2623 } 2624 }); 2625 } 2626 2627 async function publicInitFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 2628 console.info(`enter callback doInit`); 2629 let throwObject: throwObject = {isThrow: false}; 2630 try { 2631 await initSession(keyAlias, huksOptions, throwObject) 2632 .then ((data) => { 2633 console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); 2634 handle = data.handle; 2635 challenge = data.challenge as Uint8Array; 2636 }) 2637 .catch((error: BusinessError) => { 2638 if (throwObject.isThrow) { 2639 throw(error as Error); 2640 } else { 2641 console.error(`callback: doInit failed`); 2642 } 2643 }); 2644 } catch (error) { 2645 console.error(`callback: doInit input arg invalid`); 2646 } 2647 } 2648 2649 function userIAMAuthFinger(huksChallenge: Uint8Array) { 2650 // Obtain an authentication object. 2651 let auth: userIAM_userAuth.AuthInstance ; 2652 try { 2653 auth = userIAM_userAuth.getAuthInstance(huksChallenge, authType, authTrustLevel); 2654 console.log("get auth instance success"); 2655 } catch (error) { 2656 console.log("get auth instance failed" + error); 2657 return; 2658 } 2659 2660 // Subscribe to the authentication result. 2661 try { 2662 auth.on("result", { 2663 callback: (result) => { 2664 /* The authentication is successful, and the authentication token is obtained. */ 2665 fingerAuthToken = (result as userIAM_userAuth.AuthResultInfo).token as Uint8Array; 2666 } 2667 }); 2668 console.log("subscribe authentication event success"); 2669 } catch (error) { 2670 console.log("subscribe authentication event failed " + error); 2671 } 2672 2673 // Start user authentication. 2674 try { 2675 auth.start(); 2676 console.info("authV9 start auth success"); 2677 } catch (error) { 2678 console.info("authV9 start auth failed, error = " + error); 2679 } 2680 } 2681 2682 function finishSession(handle: number, huksOptions: huks.HuksOptions, token: Uint8Array, throwObject: throwObject) { 2683 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 2684 try { 2685 huks.finishSession(handle, huksOptions, token, (error, data) => { 2686 if (error) { 2687 reject(error); 2688 } else { 2689 resolve(data); 2690 } 2691 }); 2692 } catch (error) { 2693 throwObject.isThrow = true; 2694 throw(error as Error); 2695 } 2696 }); 2697 } 2698 2699 async function publicFinishFunc(handle: number, token: Uint8Array, huksOptions: huks.HuksOptions) { 2700 console.info(`enter callback doFinish`); 2701 let throwObject: throwObject = {isThrow: false}; 2702 try { 2703 await finishSession(handle, huksOptions, token, throwObject) 2704 .then ((data) => { 2705 finishOutData = data.outData as Uint8Array; 2706 console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); 2707 }) 2708 .catch((error: BusinessError) => { 2709 if (throwObject.isThrow) { 2710 throw(error as Error); 2711 } else { 2712 console.error(`callback: doFinish failed`); 2713 } 2714 }); 2715 } catch (error) { 2716 console.error(`callback: doFinish input arg invalid`); 2717 } 2718 } 2719 2720 async function testSm4Cipher() { 2721 /* Initialize the key session to obtain a challenge. */ 2722 await publicInitFunc(srcKeyAlias, decryptOptions); 2723 2724 /* Invoke userIAM to perform user identity authentication. */ 2725 userIAMAuthFinger(challenge); 2726 2727 /* Perform decryption after the authentication is successful. The **authToken** value obtained by Auth needs to be passed in. */ 2728 decryptOptions.inData = StringToUint8Array(cipherText); 2729 await publicFinishFunc(handle, fingerAuthToken, decryptOptions); 2730 } 2731 ``` 2732 2733## Key Attestation 2734 2735The HUKS provides attestation for the public keys of asymmetric key pairs. The HUKS can issue a certificate for the public key of an asymmetric key pair stored in the HUKS using the public key infrastructure (PKI) certificate chain technology. The certificate can prove the validity of the public key. The service can use the root CA certificate provided by the OpenHarmony to verify the key certificate issued by the HUKS level by level to ensure that the public key and private key in the certificate are from a trusted hardware device and stored in the HUKS. 2736 2737**How to Develop** 2738 27391. Pass in the key alias and the property tag of the key to be attested. 27402. Call a HUKS API to generate an X.509 certificate chain, which consists of the root CA certificate, device CA certificate, device certificate, and key certificate in sequence, for the application. 27413. Send the certificate chain to a trusted server. The server parses and verifies the validity of the certificate chain and whether a single certificate is revoked. 2742 2743**Available APIs** 2744 2745**Table 8** API for key attestation 2746| API | Description | 2747| -------------------------------------- | ----------------------------| 2748|attestKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback\<HuksReturnResult>) : void| Attests a key.| 2749 2750**How to Develop** 2751 2752```ts 2753/* 2754 * Attest a key and return the result in a callback. 2755 */ 2756import huks from '@ohos.security.huks'; 2757import { BusinessError } from '@ohos.base'; 2758 2759/* 2760 * Set the key alias and encapsulate the key properties. 2761 */ 2762let keyAliasString = "key attest"; 2763let aliasString = keyAliasString; 2764let aliasUint8 = StringToUint8Array(keyAliasString); 2765let securityLevel = StringToUint8Array('sec_level'); 2766let challenge = StringToUint8Array('challenge_data'); 2767let versionInfo = StringToUint8Array('version_info'); 2768let attestCertChain: Array<string>; 2769 2770class throwObject { 2771 isThrow: boolean = false; 2772} 2773 2774class genKeyPropertyType { 2775 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ALGORITHM; 2776 value: huks.HuksKeyAlg | huks.HuksKeyStorageType | huks.HuksKeySize | huks.HuksKeyPurpose | huks.HuksKeyDigest 2777 | huks.HuksKeyPadding | huks.HuksKeyGenerateType | huks.HuksCipherMode = huks.HuksKeyAlg.HUKS_ALG_RSA 2778} 2779 2780let genKeyProperties: genKeyPropertyType[] = [ 2781 { 2782 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 2783 value: huks.HuksKeyAlg.HUKS_ALG_RSA 2784 }, 2785 { 2786 tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, 2787 value: huks.HuksKeyStorageType.HUKS_STORAGE_PERSISTENT 2788 }, 2789 { 2790 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 2791 value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_2048 2792 }, 2793 { 2794 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 2795 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY 2796 }, 2797 { 2798 tag: huks.HuksTag.HUKS_TAG_DIGEST, 2799 value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 2800 }, 2801 { 2802 tag: huks.HuksTag.HUKS_TAG_PADDING, 2803 value: huks.HuksKeyPadding.HUKS_PADDING_PSS 2804 }, 2805 { 2806 tag: huks.HuksTag.HUKS_TAG_KEY_GENERATE_TYPE, 2807 value: huks.HuksKeyGenerateType.HUKS_KEY_GENERATE_TYPE_DEFAULT 2808 }, 2809 { 2810 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 2811 value: huks.HuksCipherMode.HUKS_MODE_ECB 2812 } 2813] 2814 2815let genOptions: huks.HuksOptions = { 2816 properties: genKeyProperties 2817}; 2818 2819class attestKeypropertyType { 2820 tag: huks.HuksTag = huks.HuksTag.HUKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO; 2821 value: Uint8Array = securityLevel; 2822} 2823 2824let attestKeyproperties: attestKeypropertyType[] = [ 2825 { 2826 tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO, 2827 value: securityLevel 2828 }, 2829 { 2830 tag: huks.HuksTag.HUKS_TAG_ATTESTATION_CHALLENGE, 2831 value: challenge 2832 }, 2833 { 2834 tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_VERSION_INFO, 2835 value: versionInfo 2836 }, 2837 { 2838 tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_ALIAS, 2839 value: aliasUint8 2840 } 2841] 2842 2843let huksOptions: huks.HuksOptions = { 2844 properties: attestKeyproperties 2845}; 2846 2847function StringToUint8Array(str: string) { 2848 let arr: number[] = []; 2849 for (let i = 0, j = str.length; i < j; ++i) { 2850 arr.push(str.charCodeAt(i)); 2851 } 2852 return new Uint8Array(arr); 2853} 2854 2855function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 2856 return new Promise<void>((resolve, reject) => { 2857 try { 2858 huks.generateKeyItem(keyAlias, huksOptions, (error, data) => { 2859 if (error) { 2860 reject(error); 2861 } else { 2862 resolve(data); 2863 } 2864 }); 2865 } catch (error) { 2866 throwObject.isThrow = true; 2867 throw(error as Error); 2868 } 2869 }); 2870} 2871 2872async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 2873 console.info(`enter callback generateKeyItem`); 2874 let throwObject: throwObject = {isThrow: false}; 2875 try { 2876 await generateKeyItem(keyAlias, huksOptions, throwObject) 2877 .then((data) => { 2878 console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); 2879 }) 2880 .catch((error: BusinessError) => { 2881 if (throwObject.isThrow) { 2882 throw(error as Error); 2883 } else { 2884 console.error(`callback: generateKeyItem failed`); 2885 } 2886 }); 2887 } catch (error) { 2888 console.error(`callback: generateKeyItem input arg invalid`); 2889 } 2890} 2891 2892function attestKeyItem(keyAlias: string, huksOptions: huks.HuksOptions, throwObject: throwObject) { 2893 return new Promise<huks.HuksReturnResult>((resolve, reject) => { 2894 try { 2895 huks.attestKeyItem(keyAlias, huksOptions, (error, data) => { 2896 if (error) { 2897 reject(error); 2898 } else { 2899 resolve(data); 2900 } 2901 }); 2902 } catch (error) { 2903 throwObject.isThrow = true; 2904 throw(error as Error); 2905 } 2906 }); 2907} 2908 2909async function publicAttestKey(keyAlias: string, huksOptions: huks.HuksOptions) { 2910 console.info(`enter callback attestKeyItem`); 2911 let throwObject: throwObject = {isThrow: false}; 2912 try { 2913 await attestKeyItem(keyAlias, huksOptions, throwObject) 2914 .then ((data) => { 2915 console.info(`callback: attestKeyItem success, data = ${JSON.stringify(data)}`); 2916 if (data !== null && data.certChains !== null) { 2917 attestCertChain = data.certChains as string[]; 2918 } 2919 }) 2920 .catch((error: BusinessError) => { 2921 if (throwObject.isThrow) { 2922 throw(error as Error); 2923 } else { 2924 console.error(`callback: attestKeyItem failed`); 2925 } 2926 }); 2927 } catch (error) { 2928 console.error(`callback: attestKeyItem input arg invalid`); 2929 } 2930} 2931 2932async function AttestKeyTest() { 2933 await publicGenKeyFunc(aliasString, genOptions); 2934 2935 await publicAttestKey(aliasString, huksOptions); 2936 console.info('attest certChain data: ' + attestCertChain) 2937} 2938``` 2939 2940## FAQs 2941 2942### Cannot find name 'huks'. 2943 2944**security.huks.d.ts** is not imported. To solve the problem, add **import huks from '@ohos.security.huks'**. 2945 2946### Property 'finishSession' does not exist on type 'typeof huks'. Did you mean 'finish'? 2947 2948 **finishSession()** is supported from API version 9. Update the SDK version or use the latest **security.huks.d.ts** file. 2949