From 01ed63afcc5f03b98f885ab7c4210a8e1d2ffb8c Mon Sep 17 00:00:00 2001 From: Annie_wang Date: Thu, 3 Aug 2023 11:45:02 +0800 Subject: [PATCH] update docs Signed-off-by: Annie_wang --- en/application-dev/security/huks-overview.md | 14 +- .../subsystems/figures/HUKS-architecture.png | Bin 0 -> 63412 bytes .../subsystems/subsys-security-huks-guide.md | 1139 ++++++++++++----- 3 files changed, 816 insertions(+), 337 deletions(-) create mode 100644 en/device-dev/subsystems/figures/HUKS-architecture.png diff --git a/en/application-dev/security/huks-overview.md b/en/application-dev/security/huks-overview.md index 18a1a076bf..b51c57abae 100644 --- a/en/application-dev/security/huks-overview.md +++ b/en/application-dev/security/huks-overview.md @@ -23,29 +23,29 @@ Before using the HUKS for development, you are advised to understand the followi - HUKS Core - HUKS Core is a core component that implements functions, including cryptographic calculation of keys, encryption and decryption of plaintext keys, and key access control. Generally, it runs in a secure environment (such as the TEE or security chip) of the device to ensure that the keys in plaintext are always in the HUKS Core. + HUKS Core is a core component that implements functions, including cryptographic calculation of keys, encryption and decryption of plaintext keys, and key access control. Generally, it runs in a secure environment such as a Trusted Execution Environment (TEE) or a secure chipset of the device to ensure that the keys in plaintext are always in the HUKS Core. - Key session - A key session holds information about the key operation date, key information, and access control attributes when a key is used. You need to pass in a key alias to create a session for the key. The HUKS generates a globally unique handle for each session. A general key operation involves creating a session, passing in data and parameters, and finalizing the session (or aborting the session). + A key session holds the key information, including the key operation data, key properties, and access control attributes, when a key is used. You need to pass in a key alias to create a session for the key. The HUKS generates a globally unique handle for each session. A general key operation involves creating a session, passing in data and parameters, and finishing the session (or aborting the session). ## Working Principles The security design of the HUKS includes the following: -- Always keep keys in a secure environment. +- Keys in a secure environment in lifecycle In the lifecycle of a key, the plaintext will never be exposed outside the HUKS Core. For the devices with a Trusted Execution Environment (TEE) or secure chipset, the HUKS Core runs in the TEE or secure chipset. This prevents the key plaintext from being disclosed even if the Rich Execution Environment (REE) is cracked. -- Encrypt keys for storage. +- Encrypted keys for storage The service keys are encrypted based on the device root key. Some keys can be protected by passwords if the devices support this feature. -- Apply strict access control over keys. +- Strict access control over keys Only authorized services can access keys. For security-sensitive services, user identity authentication can be enabled for key access. -- Provide key attestation. +- Key attestation - The HUKS provides attestation for hardware-backed key storage. It proves that the key has not been tampered with, is stored in the hardware-backed HUKS Core, and has correct key attributes. + The HUKS provides attestation for hardware-backed key storage. It proves that the key has not been tampered with, is stored in the hardware-backed HUKS Core, and has correct key properties. A key session is the basis for key operations in the HUKS. It initializes key information and caches the service data. Cryptographic operations on data and encryption and decryption are performed in the HUKS Core for security purposes. diff --git a/en/device-dev/subsystems/figures/HUKS-architecture.png b/en/device-dev/subsystems/figures/HUKS-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..3cb0916925b1737af0c69cb082ec91ad20fb66c1 GIT binary patch literal 63412 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 Ml~int32_t HuksHdiModuleInit(); +
int32_t ModuleInit(struct IHuks *self);
+
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  
+
Return Value - - **HKS_SUCCESS**: The operation is successful. + - **HKS_SUCCESS** (the value is **0**): The operation is successful. - - Other value: The operation failed. + - Other values (negative number): The operation fails. For details, see HksErrorCode.
- - - -#### HuksHdiRefresh + +#### ModuleDestroy **API Description** -Refreshes the root key. +Destroys the HUKS Core. You can use this API to release global variables including the locks and destroy the AuthToken key and root key in the memory. **Prototype** -
int32_t HuksHdiRefresh();
+
int32_t ModuleDestroy(struct IHuks *self);
+
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  
+
Return Value - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails.
- - - -#### HuksHdiGenerateKey +#### GenerateKey **API Description** -Generates a key based on **paramSet**. +Generate a key based on the **paramSet**. **Prototype** -
int32_t HuksHdiGenerateKey(const struct HksBlob *keyAlias, const struct HksParamSet *paramSet, const struct HksBlob *keyIn, struct HksBlob *keyOut);
+
int32_t GenerateKey(struct IHuks *self, const struct HuksBlob *keyAlias, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *keyIn, struct HuksBlob *encKeyOut);
Parameters
-  const struct HksBlob *keyAlias
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *keyAlias Pointer to the alias of the key to generate. The value must meet the following requirements: 1. keyAlias != null 2. keyAlias -> data != null - 3. keyAlias -> size != 0 + 3. keyAlias -> dataLen != 0

- const struct HksParamSet *paramSet + const struct HuksParamSet *paramSet Pointer to the parameters for generating the key.

- const struct HksBlob *keyIn - This parameter is used in key agreement. + const struct HuksBlob *keyIn + Pointer to the original key material to be passed in if the key is generated through key agreement or key derivation. This parameter is optional.

- struct HksBlob *keyOut - Pointer to the output parameter, which holds **paramSet** and the key generated. + struct HuksBlob *encKeyOut + Pointer to the key generated in ciphertext. It holds the **paramSet** and the key ciphertext in the KeyBlob format.
+

@@ -171,41 +225,44 @@ Generates a key based on **paramSet**. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails.
- - - -#### HuksHdiImportKey +#### ImportKey **API Description** Imports a key in plaintext. **Prototype** -
int32_t HuksHdiImportKey(const struct HksBlob *keyAlias, const struct HksBlob *key, const struct HksParamSet *paramSet, struct HksBlob *keyOut);
+
int32_t ImportKey(struct IHuks *self, const struct HuksBlob *keyAlias, const struct HuksBlob *key,
+    const struct HuksParamSet *paramSet, struct HuksBlob *encKeyOut);
Parameters
-  const struct HksBlob *msg
-  Pointer to the alias of the key to import. The value must meet the following requirements:
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *keyAlias + Pointer to the alias of the key to import. The alias must meet the following requirements: 1. keyAlias != null 2. keyAlias -> data != null - 3. keyAlias -> size != 0 + 3. keyAlias -> dataLen != 0

- const struct HksBlob *key - Pointer to the key to import. The value must meet the following requirements: + const struct HuksBlob *key + Pointer to the plaintext key material to import. For details about the key material format, see Key Material Formats. The value must meet the following requirements: 1. key != null 2. key -> data != null - 3. key -> size != 0 -

- const struct HksParamSet *paramSet - Pointer to the parameters for importing the key. + 3. key -> dataLen != 0

- struct HksBlob *keyOut - Pointer to the output parameter, which holds **paramSet** and the key imported. + const struct HuksParamSet *paramSet + Pointer to the parameters of the key to import.

+ struct HuksBlob *encKeyOut + Pointer to the imported key in ciphertext. It holds the **paramSet** and the imported key ciphertext in the KeyBlob format.


@@ -215,7 +272,7 @@ Imports a key in plaintext. 1. Check parameters in the API. For example, check for null pointers and whether the key algorithm is supported. - 2. **keyOut** must be in the **KeyBlob** format. + 2. Check that **encKeyOut** is in the KeyBlob format.

@@ -225,48 +282,54 @@ Imports a key in plaintext. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiImportWrappedKey +#### ImportWrappedKey **API Description** -Imports an encrypted key. +Imports a wrapped key. **Prototype** -
int32_t HuksHdiImportWrappedKey(const struct HksBlob *keyAlias, const struct HksBlob *wrappingUsedkey, const struct HksBlob *wrappedKeyData, const struct HksParamSet *paramSet, struct HksBlob *keyOut);
+
int32_t ImportWrappedKey(struct IHuks *self, const struct HuksBlob *wrappingKeyAlias,
+    const struct HuksBlob *wrappingEncKey, const struct HuksBlob *wrappedKeyData, const struct HuksParamSet *paramSet,
+    struct HuksBlob *encKeyOut);
Parameters
-  const struct HksBlob *KeyAlias
-  Pointer to the alias of the key to import. The value must meet the following requirements:
-  1. keyAlias != null
-  2. keyAlias -> data != null
-  3. keyAlias -> size != 0
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *wrappingKeyAlias + Pointer to the alias of the key used to encrypt the key to import (it is not the alias of the key to import). The value must meet the following requirements: + 1. wrappingKeyAlias != null + 2. wrappingKeyAlias -> data != null + 3. wrappingKeyAlias -> dataLen != 0

- const struct HksBlob *key + const struct HuksBlob *wrappingEncKey Pointer to the key used to encrypt the key to import. The value must meet the following requirements: - 1. wrappingUsedkey != null - 2. wrappingUsedkey -> data != null - 3. wrappingUsedkey -> size != 0 + 1. wrappingEncKey != null + 2. wrappingEncKey -> data != null + 3. wrappingEncKey -> dataLen != 0

- const struct HksBlob *wrappedKeyData - Pointer to the encrypted data of the key to import. The value must meet the following requirements: + const struct HuksBlob *wrappedKeyData + Pointer to the key material of the key to import. For details abut the key material format, see Importing a Key Securely. The value must meet the following requirements: 1. wrappedKeyData != null 2. wrappedKeyData -> data != null - 3. wrappedKeyData -> size != 0 + 3. wrappedKeyData -> dataLen != 0

- const struct HksParamSet *paramSet - Pointer to the parameters for importing the key. + const struct HuksParamSet *paramSet + Pointer to the properties of the key to import.

- struct HksBlob *keyOut - Pointer to the output parameter, which holds **paramSet** and the key imported. + struct HuksBlob *encKeyOut + Pointer to the imported key material (ciphertext) in the KeyBlob format.
+

@@ -274,7 +337,7 @@ Imports an encrypted key. 1. Check parameters in the API. For example, check for null pointers and whether the key algorithm is supported. - 2. **keyOut** must be in the **KeyBlob** format. + 2. Check that **encKeyOut** is in the KeyBlob format.


@@ -284,34 +347,38 @@ Imports an encrypted key. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiExportPublicKey +#### ExportPublicKey **API Description** -Exports a public key. +Exports the public key of a key pair. **Prototype** -
int32_t HuksHdiExportPublicKey(const struct HksBlob *key, const struct HksParamSet *paramSet, struct HksBlob *keyOut);
+
int32_t ExportPublicKey(struct IHuks *self, const struct HuksBlob *encKey,
+    const struct HuksParamSet *paramSet, struct HuksBlob *keyOut);
Parameters
-  const struct HksBlob *key
-  Pointer to the private key corresponding to the public key to export. The value must meet the following requirements:
-  1. key != null
-  2. key -> data != null
-  3. key -> size != 0
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *encKey + Pointer to the key pair material. The value must meet the following requirements: + 1. encKey != null + 2. encKey -> data != null + 3. encKey -> dataLen != 0

- const struct HksParamSet *paramSet - Pointer to the parameter set, which is empty. + const struct HuksParamSet *paramSet + Pointer to the parameters for exporting the public key. By default, this parameter is left blank.

- struct HksBlob *keyOut - Pointer to the output parameter, which holds the public key exported. + struct HuksBlob *keyOut + Pointer to the public key exported.


@@ -321,39 +388,51 @@ Exports a public key. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiInit +#### Init **API Description** -Initializes data for a key operation. This API is of the Init-Update-Final model. +Initializes a key session. You need to pass in the key material in ciphertext. The HUKS Core decrypts the ciphertext and generates a key session handle and an authentication token (if required). **Prototype** -
int32_t HuksHdiInit(const struct HksBlob *key, const struct HksParamSet *paramSet, struct HksBlob *handle, struct HksBlob *token);
+
int32_t Init(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+    struct HuksBlob *handle, struct HuksBlob *token);
Parameters
-  const struct HksBlob *key
-  Pointer to the key, on which the **Init** operation is to perform. The value must meet the following requirements:
-  1. key != null
-  2. key -> data != null
-  3. key -> size != 0
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- const struct HksParamSet *paramSet - Pointer to the parameters of the **Init** operation. + const struct HuksBlob *encKey + Pointer to the ciphertext material of the key to be operated. The value must meet the following requirements: + 1. encKey != null + 2. encKey -> data != null + 3. encKey -> dataLen != 0

- struct HksBlob *handle - Pointer to the handle of Init-Update-Finish. + const struct HuksParamSet *paramSet + Pointer to the parameters for initializing the key session.

- struct HksBlob *token - Pointer to the challenge used for secure access control. + struct HuksBlob *handle + Pointer to the key session handle generated, which identifies the key session in Update(), Finish(), and Abort(). +

+ struct HuksBlob *token + Pointer to the authentication token generated for key access control (if required).
+ +

+ +
+ Constraints +This API must be used with **Update()**, **Finish()**, and **Abort()** together. + +


@@ -361,34 +440,38 @@ Initializes data for a key operation. This API is of the Init-Update-Final model - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails.
- - - -#### HuksHdiUpdate +#### Update **API Description** -Operates data by segment or appends data for the key operation. This API is of the Init-Update-Final model. +Updates data for the key operation by segment according to the cryptographic algorithm requirements. **Prototype** -
int32_t HuksHdiUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, struct HksBlob *outData);
+
int32_t Update(struct IHuks *self, const struct HuksBlob *handle, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *inData, struct HuksBlob *outData);
Parameters
-  const struct HksBlob *handle
-  Pointer to the handle of Init-Update-Finish.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- const struct HksParamSet *paramSet - Pointer to the parameters of the **Update** operation. + const struct HuksBlob *handle + Pointer to the handle of the key session.

- const struct HksBlob *inData - Pointer to the input of the **Update** operation. + const struct HuksParamSet *paramSet + Pointer to the parameters for the update operation.

- struct HksBlob *outData - Pointer to the result of the **Update** operation. + const struct HuksBlob *inData + Pointer to the data to be passed in. +

+ struct HuksBlob *outData + Pointer to the result of the update operation.


@@ -396,7 +479,9 @@ Operates data by segment or appends data for the key operation. This API is of t
Constraints - 1. **inData** must pass in the raw data when signing and signature verification are performed. + 1. This API must be used with **Init()**, **Finish()**, and **Abort()** together. + + 2. **inData** must pass in the raw data when signature verification is performed.


@@ -406,34 +491,38 @@ Operates data by segment or appends data for the key operation. This API is of t - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiFinish +#### Finish **API Description** -Finalizes the key operation. This API is of the Init-Update-Final model. +Finishes the key session. **Prototype** -
int32_t HuksHdiFinish(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, struct HksBlob *outData);
+
int32_t Finish(struct IHuks *self, const struct HuksBlob *handle, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *inData, struct HuksBlob *outData);
Parameters
-  const struct HksBlob *handle
-  Pointer to the handle of Init-Update-Finish.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- const struct HksParamSet *paramSet - Pointer to the parameters of the **Finish** operation. + const struct HuksBlob *handle + Pointer to the handle of the key session.

- const struct HksBlob *inData - Pointer to the input of the **Finish** operation. + const struct HuksParamSet *paramSet + Pointer to the parameters for the last operation.

- struct HksBlob *outData - Pointer to the result of the **Finish** operation. + const struct HuksBlob *inData + Pointer to the last data to be passed in. +

+ struct HuksBlob *outData + Pointer to the result of the key operation.


@@ -441,7 +530,9 @@ Finalizes the key operation. This API is of the Init-Update-Final model.
Constraints - 1. In signing and signature verification, **inData** must pass in the signature data to be verified. The return value indicates whether the operation is successful. + 1. This API must be used with **Init()**, **Update()**, and **Abort()** together. + + 2. In signature verification, **inData** must pass in the signature data to be verified. The return value indicates whether the signature has passed the verification.


@@ -451,30 +542,40 @@ Finalizes the key operation. This API is of the Init-Update-Final model. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiAbort +#### Abort **API Description** -Aborts Init-Update-Finish. When an error occurs in any of the **Init**, **Update**, and **Finish** operations, call this API to terminate the use of the key. +Aborts the key session. When an error occurs in any of the **Init**, **Update**, and **Finish** operations, call this API to terminate the key session. **Prototype** -
int32_t HuksHdiAbort(const struct HksBlob *handle, const struct HksParamSet *paramSet);
- +
int32_t Abort(struct IHuks *self, const struct HuksBlob *handle, const struct HuksParamSet *paramSet);
Parameters
-  const struct HksBlob *handle
-  Pointer to the handle of Init-Update-Finish.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- const struct HksParamSet *paramSet - Pointer to the parameters of the **Abort** operation. + const struct HuksBlob *handle + Pointer to the handle of the key session. +

+ const struct HuksParamSet *paramSet + Pointer to the parameters of the Abort() operation.
+ +

+ +
+ Constraints +This API must be used with **Init()**, **Update()**, and **Finish()** together. + +


@@ -482,28 +583,32 @@ Aborts Init-Update-Finish. When an error occurs in any of the **Init**, **Update - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails.
- - - -#### HuksHdiGetKeyProperties +#### CheckKeyValidity **API Description** -Obtains key properties. +Checks key validity. **Prototype** -
int32_t HuksHdiGetKeyProperties(const struct HksParamSet *paramSet, const struct HksBlob *key);
+
int32_t CheckKeyValidity(struct IHuks *self, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *encKey);
Parameters
-  const struct HksParamSet *paramSet
-  Pointer to the parameter set, which is empty.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksParamSet *paramSet + Pointer to the parameters for checking the key integrity. By default, this parameter is left empty.

- const struct HksBlob *key - Pointer to the target key. + const struct HuksBlob *encKey + Pointer to the key material (ciphertext) to be checked.


@@ -513,39 +618,42 @@ Obtains key properties. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiAttestKey +#### AttestKey **API Description** -Obtains the key certificate. +Attests a key. **Prototype** -
int32_t (*HuksHdiAttestKey)(const struct HksBlob *key, const struct HksParamSet *paramSet, struct HksBlob *certChain);
+
int32_t AttestKey(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+    struct HuksBlob *certChain);
Parameters
-  const struct HksBlob *key
-  Pointer to the target key.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- const struct HksParamSet *paramSet - Pointer to the parameters for the operation. + const struct HuksBlob *encKey + Pointer to the key pair material in ciphertext.

- struct HksBlob *certChain - Pointer to the output parameter, which holds the certificate obtained. + const struct HuksParamSet *paramSet + Pointer to the parameters (such as the challenge) for obtaining the key certificate chain. +

+ struct HuksBlob *certChain + Pointer to the certificate chain obtained.


Constraints - - 1. **certChain** must comply with the certificate chain described in [Constraints](#constraints). +**certChain** must comply with the certificate chain described in [Constraints](#constraints).


@@ -555,40 +663,44 @@ Obtains the key certificate. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiExportChipsetPlatformPublicKey +#### ExportChipsetPlatformPublicKey **API Description** Exports the public key of a chipset key pair. **Prototype** -
int32_t (*HuksHdiExportChipsetPlatformPublicKey)(const struct HksBlob *salt, enum HksChipsetPlatformDecryptScene scene, struct HksBlob *publicKey);
+
int32_t ExportChipsetPlatformPublicKey(struct IHuks *self, const struct HuksBlob *salt,
+    enum HuksChipsetPlatformDecryptScene scene, struct HuksBlob *publicKey);
Parameters
-  const struct HksBlob *salt
-  Factor used to derive the chipset key pair.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- enum HksChipsetPlatformDecryptScene scene - Expected chipset platform decryption scenario. + const struct HuksBlob *salt + Pointer to the factor used to derive the chipset key pair.

- struct HksBlob *publicKey - The output parameters are the raw data of ECC P-256 x-axis and y-axis values, each of which are of 32 bytes. + enum HuksChipsetPlatformDecryptScene scene + Expected chipset decryption scenario. +

+ struct HuksBlob *publicKey + Pointer to the raw data of ECC P-256 x-axis and y-axis values, each of which are of 32 bytes.
+

Constraints - - 1. The input parameter **salt** must be of 16 bytes, and the content of the last byte will be ignored and filled by HUKS based on **scene**. - Currently, the chipset key pairs of HUKS are implemented by software. An ECC P-256 key pair is hard-coded, and the **salt** value is ignored. That is, the derived keys are the same regardless of the **salt**. In the hardware-based implementation of chipset key pairs, **salt** is a factor used to derive the key. That is, the key pair derived varies with the **salt** value. +The input parameter **salt** must be of 16 bytes, and the content of the last byte will be ignored and filled by HUKS based on **scene**. +Currently, the chipset key pairs of HUKS are implemented by software. An ECC P-256 key pair is hard-coded, and the **salt** value is ignored. That is, the derived keys are the same regardless of the **salt**. In the hardware-based implementation of chipset key pairs, **salt** is a factor used to derive the key. That is, the key pair derived varies with the **salt** value.


@@ -598,31 +710,35 @@ Exports the public key of a chipset key pair. - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - -#### HuksHdiUpgradeKey +#### UpgradeKey **API Description** Updates the key file when the key file version is earlier than the latest version. **Prototype** -
int32_t (*HuksHdiUpgradeKey)(const struct HksBlob *oldKey, const struct HksParamSet *paramSet, struct HksBlob *newKey);
+
int32_t UpgradeKey(struct IHuks *self, const struct HuksBlob *encOldKey, const struct HuksParamSet *paramSet,
+    struct HuksBlob *encNewKey);
Parameters
-  const struct HksBlob *oldKey
-  Key file data to update.
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
   

- const struct HksParamSet *paramSet - Parameters for updating the key file data. + const struct HuksBlob *encOldKey + Pointer to the key file data to update.

- struct HksBlob *newKey - New key file data. + const struct HuksParamSet *paramSet + Pointer to the parameters for updating the key file data. +

+ struct HuksBlob *newKey + Pointer to the new key file data.


@@ -632,40 +748,396 @@ Updates the key file when the key file version is earlier than the latest versio - **HKS_SUCCESS**: The operation is successful. - - Other value: The operation failed. + - Other values: The operation fails. - - - +#### GenerateRandom + +**API Description** + +Generates a random number. + +**Prototype** + +
int32_t GenerateRandom(struct IHuks *self, const struct HuksParamSet *paramSet, struct HuksBlob *random);
+
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksParamSet *paramSet + Pointer to the parameters of the random number to generate, such as the length. +

+ struct HuksBlob *random + Pointer to the random number generated. +
+
+ +

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### Sign + +**API Description** + +Signs data. + +**Prototype** +
int32_t Sign(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *srcData, struct HuksBlob *signature);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *encKey + Pointer to the key pair material (ciphertext) used for signing. +

+ const struct HuksParamSet *paramSet + Pointer to the parameters used for signing, such as the digest mode. +

+ const struct HuksBlob *srcData + Pointer to the data to be signed. +

+ struct HuksBlob *signature + Pointer to the signature generated. +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### Verify + +**API Description** + +Verifies a digital signature. + +**Prototype** +
int32_t Verify(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *srcData, const struct HuksBlob *signature);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *encKey + Pointer to the key pair material (ciphertext) used for signature verification. +

+ const struct HuksParamSet *paramSet + Pointer to the parameters for signature verification, such as the digest mode. +

+ const struct HuksBlob *srcData + Pointer to the data with the signature to be verified. +

+ const struct HuksBlob *signature + Pointer to the signature to verify. +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### Encrypt + +**API Description** + +Encrypts data. Different from the key session APIs that must be used together, this API completes data encryption in a single call. + +**Prototype** +
int32_t Encrypt(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+     const struct HuksBlob *plainText, struct HuksBlob *cipherText);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *encKey + Pointer to the key material (ciphertext) used for encryption. +

+ const struct HuksParamSet *paramSet + Pointer to the key parameters for encryption, such as the key working mode and padding mode. +

+ const struct HuksBlob *plainText + Pointer to the plaintext data to encrypt. +

+ const struct HuksBlob *cipherText + Pointer to the encrypted data (data in ciphertext). +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### Decrypt + +**API Description** + +Decrypts data. Different from the key session APIs that must be used together, this API completes data decryption in a single call. + +**Prototype** +
int32_t Decrypt(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *cipherText, struct HuksBlob *plainText);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *encKey + Pointer to the key material (ciphertext) used for decryption. +

+ const struct HuksParamSet *paramSet + Pointer to the key parameters for decryption, such as the key working mode and padding mode. +

+ const struct HuksBlob *cipherText + Pointer to the data to decrypt. +

+ const struct HuksBlob *plainText + Pointer to the encrypted data in plaintext. +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### AgreeKey + +**API Description** + +Performs key agreement. Different from the key session APIs that must be used together, this API returns an agreed key in a single call. + +**Prototype** +
int32_t AgreeKey(struct IHuks *self, const struct HuksParamSet *paramSet,
+    const struct HuksBlob *encPrivateKey, const struct HuksBlob *peerPublicKey, struct HuksBlob *agreedKey);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksParamSet *paramSet + Pointer to the parameters for key agreement, such as the length of the agreed key. +

+ const struct HuksBlob *encPrivateKey + Pointer to the private key material (ciphertext) used for key agreement. +

+ const struct HuksBlob *peerPublicKey + Pointer to the public key (plaintext) used for key agreement. +

+ struct HuksBlob *agreedKey + Pointer to the agreed key in plaintext. +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### DeriveKey + +**API Description** + +Derives a key. Different from the key session APIs that must be used together, this API derives a key in a single call. + +**Prototype** +
int32_t DeriveKey(struct IHuks *self, const struct HuksParamSet *paramSet, const struct HuksBlob *encKdfKey,
+     struct HuksBlob *derivedKey);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksParamSet *paramSet + Pointer to the parameters for key derivation, such as the length of the derived key. +

+ const struct HuksBlob *encKdfKey + Pointer to the key material (ciphertext) used for deriving a key. +

+ struct HuksBlob *derivedKey + Pointer to the derived key in plaintext. +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - + +#### Mac + +**API Description** + +Generates a MAC based on the given key. + +**Prototype** +
int32_t Mac(struct IHuks *self, const struct HuksBlob *encKey, const struct HuksParamSet *paramSet,
+     const struct HuksBlob *srcData, struct HuksBlob *mac);
+ +
+ Parameters +
+  struct IHuks *self
+  Pointer to the HUKS HDI struct.
+  

+ const struct HuksBlob *encKey + Pointer to the key material (ciphertext) used to generate the MAC. +

+ const struct HuksParamSet *paramSet + Pointer to the parameters for generating the MAC. +

+ const struct HuksBlob *srcData + Pointre to the source data for which the MAC is to be generated. +

+ struct HuksBlob *mac + Pointer to the MAC generated. +
+
+

+ +
+ Return Value + + - **HKS_SUCCESS**: The operation is successful. + + - Other values: The operation fails. +
+ +- - - ### Development Procedure -The directory structure is as follows: +#### Directory Structure + +The code for HDI adaptation is in the following directory. + +```undefined +//drivers_peripheral/huks +├── BUILD.gn # Build script. +├── hdi_service # Dependency loaded from libhuks_engine_core_standard.z.so (software implementation of the HUKS Core for reference only) by using dlopen(). + ├── huks_sa_type.h # Defines the data structs used in the HUKS service layer. + ├── huks_sa_hdi_struct.h # Defines the function pointer structs in libhuks_engine_core_standard.z.so. + ├── huks_hdi_template.h # Defines the conversion between the data structs of the HUKS service layer and the HDI. + ├── huks_hdi_service.c # Implementation of the HUKS passthrough HDI APIs. + └── huks_hdi_passthrough_adapter.c # Adaptation of HUKS passthrough HDI APIs to the HUKS Core. +└── test # Test code for the HUKS HDI APIs. + ├── BUILD.gn # Build script. + ├── fuzztest # Fuzz test. + └── unittest # Unit test. +``` + +The code of the HUKS Core software implementation is in the following directory. ```undefined -// base/security/user_auth/services/huks_standard/huks_engine/main -├── BUILD.gn # Build script -├── core_dependency # Dependencies of the implementation -└── core # Software implementation of the HUKS Core - ├── BUILD.gn # Build script +//base/security/huks/services/huks_standard/huks_engine +├── BUILD.gn # Build script. +├── core_dependency # HUKS Core dependency. +└── core # Software implementation of the HUKS Core. + ├── BUILD.gn # Build script. ├── include └── src - ├── hks_core_interfaces.c # Adaptation of the HDI to the HUKS Core - └── hks_core_service.c # Specific implementation - └── ... # Other function code + ├── hks_core_interfaces.c # Adaptation of the HDI to the HUKS Core. + └── hks_core_service.c # HUKS Core implementation. + └── ... # Code of other functions. ``` +**CAUTION** + +The software implementation of the HUKS Core contains hard-coded sensitive data, including the root key, AuthToken key for access control, key used to encrypt AuthToken, and certificate. You need to replace these code with your own implementation. /summary> + + - Root key + + The root key is used to encrypt the HUKS service key and is generally derived from the device root key. It is hard-coded in the HUKS Core software implementation. For details, see hks_openssl_get_main_key.c. + + - Key for generating an HMAC on AuthToken + + The key is used to generate an HMAC on AuthToken by the UserIAM for access control. The value is **huks_default_user_auth_token_key** and hard-coded in the HUKS Core software implementation. For details about the code, see hks_keyblob.c. + + - Key for encrypting sensitive fields of AuthToken + + The key is used to encrypt sensitive fields of AuthToken in access control. The value is **huks_default_user_auth_token_key** and hard-coded in the HUKS Core software implementation. For details about the code, see hks_keyblob.c. + + - Root certificate, device CA, and device certificate + + The root certificate, device CA, and device certificate are used for key attestation and preset in the secure storage of the hardware device by the device certificate management module. These certificates are hard-coded in the HUKS Core software implementation. For details about the code, see dcm_certs_and_key.h. -Init-Update-Finish must be used to implement HUKS Core APIs. The following provides the development procedure of Init-Update-Finish and sample code of the HUKS Core. You can refer to the following code to implement all HDI APIs. +#### Example -For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com/openharmony/security_huks/blob/master/services/huks_standard/huks_engine/main/core/src/hks_core_service.c). +The following uses the adaptation of the key session APIs **Init**, **Update**, and **Finish** in the HUKS Core as an example. The sample code is for reference only and cannot be used directly. For details about the executable code, see [HUKS source code](https://gitee.com/openharmony/security_huks). -1. Create a handle to enable the information about the operations on a key to be stored in a session. With this handle, multiple operations on the same key can be performed. +1. Create a handle to identify information about key operations in a session. With this handle, multiple operations on the same key can be performed. ```c - // Implement Init(). + // Initialize the key session. - int32_t HksCoreInit(const struct HksBlob *key, const struct HksParamSet *paramSet, struct HksBlob *handle, - struct HksBlob *token) + int32_t HksCoreInit(const struct HuksBlob *key, const struct HuksParamSet *paramSet, struct HuksBlob *handle, + struct HuksBlob *token) { HKS_LOG_D("HksCoreInit in Core start"); uint32_t pur = 0; @@ -686,7 +1158,7 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com HKS_LOG_E("the pointer param entered is invalid"); return HKS_ERROR_BAD_STATE; } - // Store information in a session based on the handle. The information stored can be used for the Update and Finish operations on the key. + // Store information in a session based on the handle. The information stored can be used for the Update() and Finish() operations on the key. handle->size = sizeof(uint64_t); (void)memcpy_s(handle->data, handle->size, &(keyNode->handle), handle->size); // Obtain the algorithm from the parameters. @@ -695,14 +1167,14 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com HksDeleteKeyNode(keyNode->handle); return ret; } - // Check the key parameters. + // Check key parameters. ret = HksCoreSecureAccessInitParams(keyNode, paramSet, token); if (ret != HKS_SUCCESS) { HKS_LOG_E("init secure access params failed"); HksDeleteKeyNode(keyNode->handle); return ret; } - // Obtain the initialization handler from the algorithm library based on the usage of the key. + // Obtain the initialization handler from the algorithm library based on the key purpose. uint32_t i; uint32_t size = HKS_ARRAY_SIZE(g_hksCoreInitHandler); for (i = 0; i < size; i++) { @@ -730,12 +1202,12 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com } ``` -2. Obtain the context based on the handle, and pass in data by segment or append data to obtain the operation result. +2. Obtain the context based on the handle, and pass in data by segment to obtain the operation result or append data. ```c - // Implement Update(). - int32_t HksCoreUpdate(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, - struct HksBlob *outData) + // Update data by segment. + int32_t HksCoreUpdate(const struct HuksBlob *handle, const struct HuksParamSet *paramSet, const struct HuksBlob *inData, + struct HuksBlob *outData) { HKS_LOG_D("HksCoreUpdate in Core start"); uint32_t pur = 0; @@ -748,7 +1220,7 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com uint64_t sessionId; struct HuksKeyNode *keyNode = NULL; - // Obtain the context based on the handle. + // Obtain the context required for the key session operation based on the handle. int32_t ret = GetParamsForUpdateAndFinish(handle, &sessionId, &keyNode, &pur, &alg); if (ret != HKS_SUCCESS) { HKS_LOG_E("GetParamsForCoreUpdate failed"); @@ -766,7 +1238,7 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com uint32_t size = HKS_ARRAY_SIZE(g_hksCoreUpdateHandler); for (i = 0; i < size; i++) { if (g_hksCoreUpdateHandler[i].pur == pur) { - struct HksBlob appendInData = { 0, NULL }; + struct HuksBlob appendInData = { 0, NULL }; ret = HksCoreAppendAuthInfoBeforeUpdate(keyNode, pur, paramSet, inData, &appendInData); if (ret != HKS_SUCCESS) { HKS_LOG_E("before update: append auth info failed"); @@ -796,12 +1268,12 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com } ``` -3. Finalize the key operation to obtain the result, and destroy the handle. +3. Finish the key operation to obtain the result, and destroy the handle. ```c - // Implement Finish(). - int32_t HksCoreFinish(const struct HksBlob *handle, const struct HksParamSet *paramSet, const struct HksBlob *inData, - struct HksBlob *outData) + // Finish the key session operation. + int32_t HksCoreFinish(const struct HuksBlob *handle, const struct HuksParamSet *paramSet, const struct HuksBlob *inData, + struct HuksBlob *outData) { HKS_LOG_D("HksCoreFinish in Core start"); uint32_t pur = 0; @@ -814,7 +1286,7 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com uint64_t sessionId; struct HuksKeyNode *keyNode = NULL; - // Obtain the context based on the handle. + // Obtain the context required for the key session operation based on the handle. int32_t ret = GetParamsForUpdateAndFinish(handle, &sessionId, &keyNode, &pur, &alg); if (ret != HKS_SUCCESS) { HKS_LOG_E("GetParamsForCoreUpdate failed"); @@ -833,7 +1305,7 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com for (i = 0; i < size; i++) { if (g_hksCoreFinishHandler[i].pur == pur) { uint32_t outDataBufferSize = (outData == NULL) ? 0 : outData->size; - struct HksBlob appendInData = { 0, NULL }; + struct HuksBlob appendInData = { 0, NULL }; ret = HksCoreAppendAuthInfoBeforeFinish(keyNode, pur, paramSet, inData, &appendInData); if (ret != HKS_SUCCESS) { HKS_LOG_E("before finish: append auth info failed"); @@ -863,15 +1335,15 @@ For the code of other HUKS Core APIs, see [hks_core_service.c](https://gitee.com } ``` -### Verification +### Debugging -Use the [HUKS JS APIs](https://gitee.com/openharmony/security_huks/blob/master/interfaces/kits/js/@ohos.security.huks.d.ts) to develop a JavaScript application to verify HUKS capabilities. +Use [HUKS JS APIs](https://gitee.com/openharmony/security_huks/blob/master/interfaces/kits/js/@ohos.security.huks.d.ts) to develop a JavaScript application to verify HUKS capabilities. -The JS API corresponding to each HDI API is provided in [Available APIs](#available-apis). You can invoke the JS APIs to verify the capabilities of the corresponding HDI APIs or perform complete key operations to verify the capabilities of the APIs. +The JS APIs corresponding to HDI APIs are provided in [Available APIs](#available-apis). You can use the JS APIs to verify the capabilities of the corresponding HDI APIs or perform complete key operations to verify the capabilities of the APIs. -The JS test code is as follows. If the entire process is successful, the HDI APIs are functioning. For more information about key operations, see [HUKS Development](../../application-dev/security/huks-guidelines.md). +The following JS test code is for reference only. If the entire process goes properly, the HDI APIs are functioning. For more key operation types and samples, see [huks-guidelines.md](../../application-dev/security/huks-guidelines.md). -**Generating and Encrypting an AES Key** +**Generating an AES Key and Encrypting Data** 1. Import the HUKS module. @@ -879,102 +1351,109 @@ The JS test code is as follows. If the entire process is successful, the HDI API import huks from '@ohos.security.huks' ``` -2. Call **generateKey()** to generate a key. +2. Use **generateKey()** to generate a key. ```js - var alias = 'testAlias'; - var properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_ECC - }; - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_224 - }; - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE - }; - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_NONE - }; - var options = { - properties: properties - } - var resultA = huks.generateKey(alias, options); - ``` + + let aesKeyAlias = 'test_aesKeyAlias'; + let handle; + let IV = '001122334455'; + let cipherData:Uint8Array; + let plainData:Uint8Array; -3. Call **Init()** to perform initialization. + + function GetAesGenerateProperties() { + var properties = new Array(); + var index = 0; + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES + }; + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128 + }; + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT + } + return properties; + } - ```js - var alias = 'test001' - var properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_DH - }; - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE - }; - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_4096 - }; - var options = { - properties: properties - }; - huks.init(alias, options, function(err, data) { - if (err.code !== 0) { - console.log("test init err information: " + JSON.stringify(err)); - } else { - console.log(`test init data: ${JSON.stringify(data)}`); - } - }) + + async function GenerateAesKey() { + var genProperties = GetAesGenerateProperties(); + var options = { + properties: genProperties + } + await huks.generateKeyItem(aesKeyAlias, options).then((data) => { + console.log("generateKeyItem success"); + }).catch((err)=>{ + console.log("generateKeyItem failed"); + }) + } ``` - -4. Call **update()** to perform the **Update** operation. - ```js - var properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_DH - }; - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE - }; - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_4096 - }; - var options = { - properties: properties - }; - var result = huks.update(handle, options) - ``` - -5. Call **finish()** to finalize the operation. +3. Use **huks.initSession** and **huks.finishSession** to encrypt data. ```js - var properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_DH - }; - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_AGREE - }; - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_DH_KEY_SIZE_4096 - }; - var options = { - properties: properties - }; - var result = huks.finish(handle, options) + let plainText = '123456'; + + function StringToUint8Array(str) { + let arr = []; + for (let i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + return new Uint8Array(arr); + } + + function GetAesEncryptProperties() { + var properties = new Array(); + var index = 0; + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES + }; + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128 + }; + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT + } + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_PKCS7 + } + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC + } + properties[index++] = { + tag: huks.HuksTag.HUKS_TAG_IV, + value: StringToUint8Array(IV) + } + return properties; + } + + async function EncryptData() { + var encryptProperties = GetAesEncryptProperties(); + var options = { + properties:encryptProperties, + inData: StringToUint8Array(plainText) + } + await huks.initSession(aesKeyAlias, options).then((data) => { + handle = data.handle; + }).catch((err)=>{ + console.log("initSession failed"); + }) + await huks.finishSession(handle, options).then((data) => { + console.log("finishSession success"); + cipherData = data.outData + }).catch((err)=>{ + console.log("finishSession failed"); + }) + } ``` -- GitLab