1# Importing a Key in Ciphertext (ArkTS) 2 3<!--Kit: Universal Keystore Kit--> 4<!--Subsystem: Security--> 5<!--Owner: @wutiantian-gitee--> 6<!--Designer: @HighLowWorld--> 7<!--Tester: @wxy1234564846--> 8<!--Adviser: @zengyawen--> 9 10This topic walks you through on how to import an ECDH key pair. However, the example does not cover the operations such as [key generation](huks-key-generation-overview.md) and [key agreement](huks-key-agreement-overview.md) of the service side. 11 12For details about the scenarios and supported algorithm specifications, see [Supported Algorithms](huks-key-import-overview.md#supported-algorithms). 13 14## How to Develop 15 161. Convert the key to be imported from device A (device from which the key is imported) to [HUKS key material format](huks-concepts.md#key material format) **To_Import_Key**. (This step applies only to asymmetric key pairs. If the key to be imported is a symmetric key, skip over this step.) 17 182. Generate an asymmetric key pair **Wrapping_Key** (public key **Wrapping_Pk** and private key **Wrapping_Sk**) with the purpose of **HUKS_KEY_PURPOSE_UNWRAP** for device B (device to which the key is imported), and export the public key **Wrapping_Pk** of **Wrapping_Key** and save it. The asymmetric key pair **Wrapping_Key** is used for key agreement in the encrypted import process. 19 203. Use the same algorithm to generate an asymmetric key pair **Caller_Key** (public key **Caller_Pk** and private key **Caller_Sk**) with the purpose of **HUKS_KEY_PURPOSE_UNWRAP** for device A, and export the public key **Caller_Pk** of **Caller_Key** and save it. The asymmetric key pair **Caller_Key** is used for key agreement in the encrypted import process. 21 224. Generate a symmetric key **Caller_Kek** for device A. This key is used to encrypt **To_Import_Key**. 23 245. Perform key agreement with the private key **Caller_Sk** in **Caller_Key** of device A and the public key **Wrapping_Pk** in **Wrapping_Key** of device B to yield a **Shared_Key**. 25 266. Use **Caller_Kek** to encrypt **To_Import_Key** of device A and generate **To_Import_Key_Enc**. 27 287. Use **Shared_Key** to encrypt **Caller_Kek** of device A and generate **Caller_Kek_Enc**. 29 308. Encapsulate the key material **Caller_Pk**, **Caller_Kek_Enc**, and **To_Import_Key_Enc** of device A, and sends it to device B. For details about the format of the key material to be imported, see [Key Material Format for Encrypted Import](huks-key-import-overview.md#key-material-format-for-encrypted-import). 31 329. Import the encrypted key material to device B. 33 3410. Delete the intermediate keys (keys used for encrypting the key to import) from devices A and B. 35 36```ts 37import { huks } from '@kit.UniversalKeystoreKit'; 38 39let IV = '0000000000000000'; // Replace this example code with a random value in practice. 40let AAD = "abababababababab"; 41let NONCE = 'hahahahahaha'; // Replace this example code with a random value in practice. 42let TAG_SIZE = 16; 43let FILED_LENGTH = 4; 44let importedAes192PlainKey = "The aes192 key to import"; 45let callerAes256Kek = "It's a kek to encrypt aes192 key"; 46let callerKeyAlias = "test_caller_key_ecdh_aes192"; 47let callerKekAliasAes256 = "test_caller_kek_ecdh_aes256"; 48let callerAgreeKeyAliasAes256 = "test_caller_agree_key_ecdh_aes256"; 49let importedKeyAliasAes192 = "test_import_key_ecdh_aes192"; 50let huksPubKey: Uint8Array; 51let callerSelfPublicKey: Uint8Array; 52let outSharedKey: Uint8Array; 53let outPlainKeyEncData: Uint8Array; 54let outKekEncData: Uint8Array; 55let outKekEncTag: Uint8Array; 56let outAgreeKeyEncTag: Uint8Array; 57let mask = [0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000]; 58 59function subUint8ArrayOf(arrayBuf: Uint8Array, start: number, end: number) { 60 let arr: number[] = []; 61 for (let i = start; i < end && i < arrayBuf.length; ++i) { 62 arr.push(arrayBuf[i]); 63 } 64 return new Uint8Array(arr); 65} 66 67function stringToUint8Array(str: string) { 68 let arr: number[] = []; 69 for (let i = 0, j = str.length; i < j; ++i) { 70 arr.push(str.charCodeAt(i)); 71 } 72 return new Uint8Array(arr); 73} 74 75function assignLength(length: number, arrayBuf: Uint8Array, startIndex: number) { 76 let index = startIndex; 77 for (let i = 0; i < 4; i++) { 78 arrayBuf[index++] = (length & mask[i]) >> (i * 8); 79 } 80 return 4; 81} 82 83function assignData(data: Uint8Array, arrayBuf: Uint8Array, startIndex: number) { 84 let index = startIndex; 85 for (let i = 0; i < data.length; i++) { 86 arrayBuf[index++] = data[i]; 87 } 88 return data.length; 89} 90 91let genWrappingKeyParams: huks.HuksOptions = { 92 properties: new Array<huks.HuksParam>( 93 { 94 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 95 value: huks.HuksKeyAlg.HUKS_ALG_ECC 96 }, 97 { 98 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 99 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_UNWRAP 100 }, 101 { 102 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 103 value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 104 }, 105 { 106 tag: huks.HuksTag.HUKS_TAG_PADDING, 107 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 108 } 109 ) 110} 111let genCallerEcdhParams: huks.HuksOptions = { 112 properties: new Array<huks.HuksParam>( 113 { 114 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 115 value: huks.HuksKeyAlg.HUKS_ALG_ECC 116 }, 117 { 118 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 119 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE 120 }, 121 { 122 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 123 value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 124 } 125 ) 126} 127let importParamsCallerKek: huks.HuksOptions = { 128 properties: new Array<huks.HuksParam>( 129 { 130 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 131 value: huks.HuksKeyAlg.HUKS_ALG_AES 132 }, 133 { 134 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 135 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 136 }, 137 { 138 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 139 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 140 }, 141 { 142 tag: huks.HuksTag.HUKS_TAG_PADDING, 143 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 144 }, 145 { 146 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 147 value: huks.HuksCipherMode.HUKS_MODE_GCM 148 }, 149 { 150 tag: huks.HuksTag.HUKS_TAG_DIGEST, 151 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE 152 }, 153 { 154 tag: huks.HuksTag.HUKS_TAG_IV, 155 value: stringToUint8Array(IV) 156 } 157 ), 158 inData: stringToUint8Array(callerAes256Kek) 159} 160let importParamsAgreeKey: huks.HuksOptions = { 161 properties: new Array<huks.HuksParam>( 162 { 163 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 164 value: huks.HuksKeyAlg.HUKS_ALG_AES 165 }, 166 { 167 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 168 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 169 }, 170 { 171 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 172 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 173 }, 174 { 175 tag: huks.HuksTag.HUKS_TAG_PADDING, 176 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 177 }, 178 { 179 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 180 value: huks.HuksCipherMode.HUKS_MODE_GCM 181 }, 182 { 183 tag: huks.HuksTag.HUKS_TAG_DIGEST, 184 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE 185 }, 186 { 187 tag: huks.HuksTag.HUKS_TAG_IV, 188 value: stringToUint8Array(IV) 189 } 190 ), 191} 192let callerAgreeParams: huks.HuksOptions = { 193 properties: new Array<huks.HuksParam>( 194 { 195 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 196 value: huks.HuksKeyAlg.HUKS_ALG_ECDH 197 }, 198 { 199 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 200 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE 201 }, 202 { 203 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 204 value: huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256 205 } 206 ) 207} 208let encryptKeyCommonParams: huks.HuksOptions = { 209 properties: new Array<huks.HuksParam>( 210 { 211 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 212 value: huks.HuksKeyAlg.HUKS_ALG_AES 213 }, 214 { 215 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 216 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT 217 }, 218 { 219 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 220 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 221 }, 222 { 223 tag: huks.HuksTag.HUKS_TAG_PADDING, 224 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 225 }, 226 { 227 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 228 value: huks.HuksCipherMode.HUKS_MODE_GCM 229 }, 230 { 231 tag: huks.HuksTag.HUKS_TAG_NONCE, 232 value: stringToUint8Array(NONCE) 233 }, 234 { 235 tag: huks.HuksTag.HUKS_TAG_ASSOCIATED_DATA, 236 value: stringToUint8Array(AAD) 237 } 238 ), 239} 240let importWrappedAes192Params: huks.HuksOptions = { 241 properties: new Array<huks.HuksParam>( 242 { 243 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 244 value: huks.HuksKeyAlg.HUKS_ALG_AES 245 }, 246 { 247 tag: huks.HuksTag.HUKS_TAG_PURPOSE, 248 value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | 249 huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT 250 }, 251 { 252 tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, 253 value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_192 254 }, 255 { 256 tag: huks.HuksTag.HUKS_TAG_PADDING, 257 value: huks.HuksKeyPadding.HUKS_PADDING_NONE 258 }, 259 { 260 tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, 261 value: huks.HuksCipherMode.HUKS_MODE_CBC 262 }, 263 { 264 tag: huks.HuksTag.HUKS_TAG_DIGEST, 265 value: huks.HuksKeyDigest.HUKS_DIGEST_NONE 266 }, 267 { 268 tag: huks.HuksTag.HUKS_TAG_UNWRAP_ALGORITHM_SUITE, 269 value: huks.HuksUnwrapSuite.HUKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING 270 }, 271 { 272 tag: huks.HuksTag.HUKS_TAG_IV, 273 value: stringToUint8Array(IV) 274 } 275 ) 276} 277 278async function publicGenerateItemFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 279 console.info(`enter promise generateKeyItem`); 280 try { 281 await huks.generateKeyItem(keyAlias, huksOptions) 282 .then(data => { 283 console.info(`promise: generateKeyItem success, data = ${JSON.stringify(data)}`); 284 }) 285 .catch((err: Error) => { 286 console.error(`promise: generateKeyItem failed, ${JSON.stringify(err)}`); 287 }) 288 } catch (err) { 289 console.error(`promise: generateKeyItem invalid, ${JSON.stringify(err)}`); 290 } 291} 292 293async function publicImportKeyItemFunc(keyAlias: string, huksOptions: huks.HuksOptions) { 294 console.info(`enter promise importKeyItem`); 295 try { 296 await huks.importKeyItem(keyAlias, huksOptions) 297 .then(data => { 298 console.info(`promise: importKeyItem success, data = ${JSON.stringify(data)}`); 299 }).catch((err: Error) => { 300 console.error(`promise: importKeyItem failed, ${JSON.stringify(err)}`); 301 }) 302 } catch (err) { 303 console.error(`promise: importKeyItem input arg invalid, ${JSON.stringify(err)}`); 304 } 305} 306 307async function publicDeleteKeyItemFunc(KeyAlias: string, huksOptions: huks.HuksOptions) { 308 console.info(`enter promise deleteKeyItem`); 309 try { 310 await huks.deleteKeyItem(KeyAlias, huksOptions) 311 .then(data => { 312 console.info(`promise: deleteKeyItem key success, data = ${JSON.stringify(data)}`); 313 }) 314 .catch((err: Error) => { 315 console.error(`promise: deleteKeyItem failed, ${JSON.stringify(err)}`); 316 }) 317 } catch (err) { 318 console.error(`promise: deleteKeyItem input arg invalid, ${JSON.stringify(err)}`); 319 } 320} 321 322function importWrappedKeyItem(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) { 323 return new Promise<void>((resolve, reject) => { 324 try { 325 huks.importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions, (error, data) => { 326 if (error) { 327 reject(error); 328 } else { 329 resolve(data); 330 } 331 }); 332 } catch (error) { 333 } 334 }); 335} 336 337async function publicImportWrappedKeyFunc(keyAlias: string, wrappingKeyAlias: string, huksOptions: huks.HuksOptions) { 338 console.info(`enter promise importWrappedKeyItem`); 339 for (let i = 0; i < huksOptions.inData!.length; i++) { 340 console.info(`${i}: ${huksOptions.inData![i]}`); 341 } 342 try { 343 await importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions) 344 .then((data) => { 345 console.info(`promise: importWrappedKeyItem success, data = ${JSON.stringify(data)}`); 346 }) 347 .catch((error: Error) => { 348 console.error(`promise: importWrappedKeyItem failed, ${JSON.stringify(error)}`); 349 }); 350 } catch (error) { 351 console.error(`promise: importWrappedKeyItem input arg invalid, ${JSON.stringify(error)}`); 352 } 353} 354 355async function publicInitFunc(srcKeyAlias: string, huksOptions: huks.HuksOptions) { 356 let handle: number = 0; 357 console.info(`enter promise doInit`); 358 try { 359 await huks.initSession(srcKeyAlias, huksOptions) 360 .then((data) => { 361 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 362 handle = data.handle; 363 }) 364 .catch((error: Error) => { 365 console.error(`promise: doInit key failed, ${JSON.stringify(error)}`); 366 }); 367 } catch (error) { 368 console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`); 369 } 370 return handle; 371} 372 373async function publicUpdateSessionFunction(handle: number, huksOptions: huks.HuksOptions) { 374 const maxUpdateSize = 64; 375 const inData = huksOptions.inData!; 376 const lastInDataPosition = inData.length - 1; 377 let inDataSegSize = maxUpdateSize; 378 let inDataSegPosition = 0; 379 let isFinished = false; 380 let outData: number[] = []; 381 382 while (inDataSegPosition <= lastInDataPosition) { 383 if (inDataSegPosition + maxUpdateSize > lastInDataPosition) { 384 isFinished = true; 385 inDataSegSize = lastInDataPosition - inDataSegPosition + 1; 386 console.info(`enter promise doUpdate`); 387 break; 388 } 389 huksOptions.inData = new Uint8Array( 390 Array.from(inData).slice(inDataSegPosition, inDataSegPosition + inDataSegSize) 391 ); 392 console.info(`enter promise doUpdate`); 393 try { 394 await huks.updateSession(handle, huksOptions) 395 .then((data) => { 396 console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`); 397 outData = outData.concat(Array.from(data.outData!)); 398 }) 399 .catch((error: Error) => { 400 console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`); 401 }); 402 } catch (error) { 403 console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`); 404 } 405 if ((!isFinished) && (inDataSegPosition + maxUpdateSize > lastInDataPosition)) { 406 console.error(`update size invalid isFinished = ${isFinished}`); 407 console.error(`inDataSegPosition = ${inDataSegPosition}`); 408 console.error(`lastInDataPosition = ${lastInDataPosition}`); 409 return; 410 } 411 inDataSegPosition += maxUpdateSize; 412 } 413 return outData; 414} 415 416async function publicFinishSession(handle: number, huksOptions: huks.HuksOptions, inData: number[]) { 417 let outData: number[] = []; 418 console.info(`enter promise doFinish`); 419 try { 420 await huks.finishSession(handle, huksOptions) 421 .then((data) => { 422 console.info(`promise: doFinish success, data = ${JSON.stringify(data)}`); 423 outData = inData.concat(Array.from(data.outData!)); 424 }) 425 .catch((error: Error) => { 426 console.error(`promise: doFinish key failed, ${JSON.stringify(error)}`); 427 }); 428 } catch (error) { 429 console.error(`promise: doFinish input arg invalid, ${JSON.stringify(error)}`); 430 } 431 return new Uint8Array(outData); 432} 433 434async function cipherFunction(keyAlias: string, huksOptions: huks.HuksOptions) { 435 let handle = await publicInitFunc(keyAlias, huksOptions); 436 let tmpData = await publicUpdateSessionFunction(handle, huksOptions); 437 let outData = await publicFinishSession(handle, huksOptions, tmpData!); 438 return outData; 439} 440 441async function agreeFunction(keyAlias: string, huksOptions: huks.HuksOptions, huksPublicKey: Uint8Array) { 442 let handle = await publicInitFunc(keyAlias, huksOptions); 443 let outSharedKey: Uint8Array = new Uint8Array(); 444 huksOptions.inData = huksPublicKey; 445 console.info(`enter promise doUpdate`); 446 try { 447 await huks.updateSession(handle, huksOptions) 448 .then((data) => { 449 console.info(`promise: doUpdate success, data = ${JSON.stringify(data)}`); 450 }) 451 .catch((error: Error) => { 452 console.error(`promise: doUpdate failed, ${JSON.stringify(error)}`); 453 }); 454 } catch (error) { 455 console.error(`promise: doUpdate input arg invalid, ${JSON.stringify(error)}`); 456 } 457 console.info(`enter promise doInit`); 458 try { 459 await huks.finishSession(handle, huksOptions) 460 .then((data) => { 461 console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); 462 outSharedKey = data.outData as Uint8Array; 463 }) 464 .catch((error: Error) => { 465 console.error(`promise: doInit key failed, ${JSON.stringify(error)}`); 466 }); 467 } catch (error) { 468 console.error(`promise: doInit input arg invalid, ${JSON.stringify(error)}`); 469 } 470 return outSharedKey; 471} 472 473async function ImportKekAndAgreeSharedSecret(callerKekAlias: string, importKekParams: huks.HuksOptions, 474 callerKeyAlias: string, huksPublicKey: Uint8Array, agreeParams: huks.HuksOptions) { 475 await publicImportKeyItemFunc(callerKekAlias, importKekParams); 476 outSharedKey = await agreeFunction(callerKeyAlias, agreeParams, huksPublicKey); 477 importParamsAgreeKey.inData = outSharedKey; 478 await publicImportKeyItemFunc(callerAgreeKeyAliasAes256, importParamsAgreeKey); 479} 480 481async function generateAndExportPublicKey(keyAlias: string, huksOptions: huks.HuksOptions, caller: Boolean) { 482 await publicGenerateItemFunc(keyAlias, huksOptions); 483 try { 484 await huks.exportKeyItem(keyAlias, huksOptions) 485 .then((data) => { 486 console.info(`promise: exportKeyItem success, data = ${JSON.stringify(data)}`); 487 if (caller) { 488 callerSelfPublicKey = data.outData as Uint8Array; 489 } else { 490 huksPubKey = data.outData as Uint8Array; 491 } 492 }) 493 .catch((error: Error) => { 494 console.error(`promise: exportKeyItem failed, ${JSON.stringify(error)}`); 495 }); 496 } catch (error) { 497 console.error(`promise: generate pubKey failed, ${JSON.stringify(error)}`); 498 } 499} 500 501async function EncryptImportedPlainKeyAndKek(keyAlias: string) { 502 encryptKeyCommonParams.inData = stringToUint8Array(keyAlias) 503 let plainKeyEncData = await cipherFunction(callerKekAliasAes256, encryptKeyCommonParams); 504 outKekEncTag = subUint8ArrayOf(plainKeyEncData, plainKeyEncData.length - TAG_SIZE, plainKeyEncData.length) 505 outPlainKeyEncData = subUint8ArrayOf(plainKeyEncData, 0, plainKeyEncData.length - TAG_SIZE) 506 encryptKeyCommonParams.inData = stringToUint8Array(callerAes256Kek) 507 let kekEncData = await cipherFunction(callerAgreeKeyAliasAes256, encryptKeyCommonParams) 508 outAgreeKeyEncTag = subUint8ArrayOf(kekEncData, kekEncData.length - TAG_SIZE, kekEncData.length) 509 outKekEncData = subUint8ArrayOf(kekEncData, 0, kekEncData.length - TAG_SIZE) 510} 511 512async function BuildWrappedDataAndImportWrappedKey(plainKey: string) { 513 let plainKeySizeBuff = new Uint8Array(4); 514 assignLength(plainKey.length, plainKeySizeBuff, 0); 515 let wrappedData = new Uint8Array( 516 FILED_LENGTH + huksPubKey.length + 517 FILED_LENGTH + AAD.length + 518 FILED_LENGTH + NONCE.length + 519 FILED_LENGTH + TAG_SIZE + 520 FILED_LENGTH + outKekEncData.length + 521 FILED_LENGTH + AAD.length + 522 FILED_LENGTH + NONCE.length + 523 FILED_LENGTH + TAG_SIZE + 524 FILED_LENGTH + plainKeySizeBuff.length + 525 FILED_LENGTH + outPlainKeyEncData.length 526 ); 527 let index = 0; 528 let AADUint8Array = stringToUint8Array(AAD); 529 let NonceArray = stringToUint8Array(NONCE); 530 index += assignLength(callerSelfPublicKey.length, wrappedData, index); // 4 531 index += assignData(callerSelfPublicKey, wrappedData, index); // 91 532 index += assignLength(AADUint8Array.length, wrappedData, index); // 4 533 index += assignData(AADUint8Array, wrappedData, index); // 16 534 index += assignLength(NonceArray.length, wrappedData, index); // 4 535 index += assignData(NonceArray, wrappedData, index); // 12 536 index += assignLength(outAgreeKeyEncTag.length, wrappedData, index); // 4 537 index += assignData(outAgreeKeyEncTag, wrappedData, index); // 16 538 index += assignLength(outKekEncData.length, wrappedData, index); // 4 539 index += assignData(outKekEncData, wrappedData, index); // 32 540 index += assignLength(AADUint8Array.length, wrappedData, index); // 4 541 index += assignData(AADUint8Array, wrappedData, index); // 16 542 index += assignLength(NonceArray.length, wrappedData, index); // 4 543 index += assignData(NonceArray, wrappedData, index); // 12 544 index += assignLength(outKekEncTag.length, wrappedData, index); // 4 545 index += assignData(outKekEncTag, wrappedData, index); // 16 546 index += assignLength(plainKeySizeBuff.length, wrappedData, index); // 4 547 index += assignData(plainKeySizeBuff, wrappedData, index); // 4 548 index += assignLength(outPlainKeyEncData.length, wrappedData, index); // 4 549 index += assignData(outPlainKeyEncData, wrappedData, index); // 24 550 return wrappedData; 551} 552 553/* Simulate the encrypted key import scenario. Import a key from device A (remote device) to device B (local device). */ 554async function ImportWrappedKey() { 555 /** 556 * 1. If the key to import from device A is an asymmetric key pair, convert it into the HUKS key material format **To_Import_Key**. Skip over this step if the key is a symmetric key. 557 * This example uses importedAes192PlainKey (symmetric key) as an example. 558 */ 559 560 /* 2. Generate an asymmetric key pair Wrapping_Key (public key Wrapping_Pk and private key Wrapping_Sk) with the purpose of HUKS_KEY_PURPOSE_UNWRAP for device B, export the public key Wrapping_Pk of Wrapping_Key, and save it to huksPubKey. */ 561 const srcKeyAliasWrap = 'HUKS_Basic_Capability_Import_0200'; 562 await generateAndExportPublicKey(srcKeyAliasWrap, genWrappingKeyParams, false); 563 564 /* 3. Use the same algorithm to generate an asymmetric key pair Caller_Key (public key Caller_Pk and private key Caller_Sk) with the purpose of HUKS_KEY_PURPOSE_UNWRAP for device A, export the public key Caller_Pk of Caller_Key, save it to callerSelfPublicKey. */ 565 await generateAndExportPublicKey(callerKeyAlias, genCallerEcdhParams, true); 566 567 /** 568 4. Generate a symmetric key Caller_Kek for device A. This key is used to encrypt To_Import_Key. 569 * 5. Perform key agreement with the private key Caller_Sk in Caller_Key of device A and the public key Wrapping_Pk in Wrapping_Key of device B to yield a Shared_Key. 570 */ 571 await ImportKekAndAgreeSharedSecret(callerKekAliasAes256, importParamsCallerKek, callerKeyAlias, huksPubKey, 572 callerAgreeParams); 573 574 /** 575 * 6. Use Caller_Kek to encrypt To_Import_Key of device A and generate To_Import_Key_Enc. 576 * 7. Use Shared_Key to encrypt Caller_Kek of device A and generate Caller_Kek_Enc. 577 */ 578 await EncryptImportedPlainKeyAndKek(importedAes192PlainKey); 579 580 /* 8. Encapsulate the key material Caller_Pk, To_Import_Key_Enc, and Caller_Kek_Enc of device A, and sends it to device B. In this example, Caller_Pk is placed in callerSelfPublicKey, To_Import_Key_Enc in PlainKeyEncData, and Caller_Kek_Enc in KekEncData. */ 581 let wrappedData = await BuildWrappedDataAndImportWrappedKey(importedAes192PlainKey); 582 importWrappedAes192Params.inData = wrappedData; 583 584 /* 9. Import the encapsulated key material to device B. */ 585 await publicImportWrappedKeyFunc(importedKeyAliasAes192, srcKeyAliasWrap, importWrappedAes192Params); 586 587 /* 10. Delete the intermediate keys (keys used for encrypting the key to import) from devices A and B. */ 588 await publicDeleteKeyItemFunc(srcKeyAliasWrap, genWrappingKeyParams); 589 await publicDeleteKeyItemFunc(callerKeyAlias, genCallerEcdhParams); 590 await publicDeleteKeyItemFunc(callerKekAliasAes256, callerAgreeParams); 591} 592 593``` 594 595 596## Verification 597 598Use [huks.isKeyItemExist](../../reference/apis-universal-keystore-kit/js-apis-huks.md#huksiskeyitemexist9) to check whether the key exists. If the key exists, the key is successfully imported. 599 600```ts 601import { huks } from '@kit.UniversalKeystoreKit'; 602 603/* 604 * Set the key alias and encapsulate the key property set. 605 */ 606let keyAlias = 'test_import_key_ecdh_aes192'; 607let isKeyExist: Boolean; 608let keyProperties: Array<huks.HuksParam> = [{ 609 tag: huks.HuksTag.HUKS_TAG_ALGORITHM, 610 value: huks.HuksKeyAlg.HUKS_ALG_AES, 611}]; 612let huksOptions: huks.HuksOptions = { 613 properties: keyProperties, // It cannot be empty. 614 inData: new Uint8Array(new Array()) // It cannot be empty. 615} 616try { 617 huks.isKeyItemExist(keyAlias, huksOptions, (error, data) => { 618 if (error) { 619 console.error(`callback: isKeyItemExist failed, ${JSON.stringify(error)}`); 620 } else { 621 if (data !== null && data.valueOf() !== null) { 622 isKeyExist = data.valueOf(); 623 console.info(`callback: isKeyItemExist success, isKeyExist = ${isKeyExist}`); 624 } 625 } 626 }); 627} catch (error) { 628 console.error(`callback: isKeyItemExist input arg invalid, ${JSON.stringify(error)}`); 629} 630``` 631