diff --git a/en/application-dev/security/Readme-EN.md b/en/application-dev/security/Readme-EN.md index 05d2d2864de5dc34947f43d1b54ab2480e039747..fb56f3785ad37741139906b1ed0034ad05722af0 100644 --- a/en/application-dev/security/Readme-EN.md +++ b/en/application-dev/security/Readme-EN.md @@ -11,6 +11,7 @@ - HUKS - [HUKS Overview](huks-overview.md) - [HUKS Development](huks-guidelines.md) + - [HUKS Cipher Algorithm Specifications](huks-appendix.md) - Crypto Framework - [Crypto Framework Overview](cryptoFramework-overview.md) - [Crypto Framework Development](cryptoFramework-guidelines.md) diff --git a/en/application-dev/security/figures/huks_architect.png b/en/application-dev/security/figures/huks_architect.png new file mode 100644 index 0000000000000000000000000000000000000000..854786917dc93499808fe72b2fc62e29e5ad2830 Binary files /dev/null and b/en/application-dev/security/figures/huks_architect.png differ diff --git a/en/application-dev/security/figures/huks_import_wrapped_key.png b/en/application-dev/security/figures/huks_import_wrapped_key.png new file mode 100644 index 0000000000000000000000000000000000000000..8ab098ace4f24884fa754acfc66f70b3df4b6162 Binary files /dev/null and b/en/application-dev/security/figures/huks_import_wrapped_key.png differ diff --git a/en/application-dev/security/figures/huks_key_user_auth_work_flow.png b/en/application-dev/security/figures/huks_key_user_auth_work_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..476279901c0600132f6311c7b4ab316c5319da5f Binary files /dev/null and b/en/application-dev/security/figures/huks_key_user_auth_work_flow.png differ diff --git a/en/application-dev/security/figures/huks_keymaterial_rsa_priv_struct.png b/en/application-dev/security/figures/huks_keymaterial_rsa_priv_struct.png new file mode 100644 index 0000000000000000000000000000000000000000..089588873dbc42463ec61431956b691f0703c136 Binary files /dev/null and b/en/application-dev/security/figures/huks_keymaterial_rsa_priv_struct.png differ diff --git a/en/application-dev/security/figures/huks_keymaterial_struct.png b/en/application-dev/security/figures/huks_keymaterial_struct.png new file mode 100644 index 0000000000000000000000000000000000000000..f117e7de8391b8d7914e781f7214f6a2f48957b1 Binary files /dev/null and b/en/application-dev/security/figures/huks_keymaterial_struct.png differ diff --git a/en/application-dev/security/huks-appendix.md b/en/application-dev/security/huks-appendix.md new file mode 100644 index 0000000000000000000000000000000000000000..99e76ccf150371654bbb67261a5a87c080743ed9 --- /dev/null +++ b/en/application-dev/security/huks-appendix.md @@ -0,0 +1,226 @@ +# HUKS Cipher Algorithm Specifications + +## Supported Algorithm Types and Parameter Combinations + +### Key Import/Generation + +| Algorithm                   | API Level| Supported Key Length (Bit) | +| -------------- | :---------------: | ------------------ | +| AES | 8+ | 128, 192, 256| +| RSA | 8+ | 512, 768, 1024, 2048, 3072, 4096| +| HMAC | 8+ | 8 to 1024 (inclusive)
The value must be an integer multiple of 8. | +| ECC | 8+ | 224, 256, 384, 521| +| Ed25519 | 8+ | 256 | +| X25519 | 8+ | 256 | +| DSA | 8+ | 8 to 1024 (inclusive)
The value must be an integer multiple of 8. | +| DH | 8+ | 2048, 3072, 4096 | +| SM2 | 9+ | 256 | +| SM3 | 9+ | 256 | +| SM4 | 9+ | 128 | + +### Encryption and Decryption + +| Algorithm                   | API Level| Remarks | +| ----------------------- | :----: | ---------------- | +| AES/CBC/NoPadding
AES/ECB/NoPadding
AES/CTR/NoPadding
AES/GCM/NoPadding
AES/CBC/PKCS7
AES/ECB/PKCS7 | 8+ | The initialization vector (IV) is mandatory in CBC, ECB, or CTR mode.
The **Nonce**, **AAD**, and **AEAD** parameters are mandatory in GCM mode. | +| RSA/ECB/NoPadding
RSA/ECB/PKCS1_V1_5
RSA/ECB/OAEP | 8+ | | +| SM4/CTR/NoPadding
SM4/ECB/NoPadding
SM4/CBC/NoPadding
SM4/ECB/PKCS7
SM4/CBC/PKCS7 | 9+ | | + + + +### Signing and Signature Verification + + +| Algorithm | API Level| Remarks | +| --------- | :----------: | ----------------- | +| RSA/MD5/PKCS1_V1_5
RSA/SHA1/PKCS1_V1_5
RSA/SHA224/PKCS1_V1_5
RSA/SHA256/PKCS1_V1_5
RSA/SHA384/PKCS1_V1_5
RSA/SHA512/PKCS1_V1_5
RSA/SHA1/PSS
RSA/SHA224/PSS
RSA/SHA256/PSS
RSA/SHA384/PSS | 8+ | | +| RSA/NoDigest/PKCS1_V1_5 | 9+ | | +| DSA/SHA1
DSA/SHA224
DSA/SHA256
DSA/SHA384
DSA/SHA512 | 8+ | | +| DSA/NoDigest | 9+ | | +| ECC/SHA1
ECC/SHA224
ECC/SHA256
ECC/SHA384
ECC/SHA512 | 8+ | | +| ECC/NoDigest | 9+ | | +| ED25519/SHA1
ED25519/SHA224
ED25519/SHA256
ED25519/SHA384
ED25519/SHA512 |8+ | | +| ED25519/NoDigest | 9+ | | +| SM2/SM3
SM2/NoDigest |9+ | | + +### Key Agreement + +| Algorithm                   | API Level| Remarks | +| ------ | :-----------: | ------------------------------ | +| ECDH | 8+ | The key must be of the ECC type. | +| DH | 8+ | | +| X25519 | 8+ | | + +### Key Derivation + +| Algorithm                   |API Level | Derived Key and Length (Bit) | Remarks | +| ------------------------- | :-----------: | :----------: | ----------------- | +| HKDF/SHA256
HKDF/SHA384
HKDF/SHA512 | 8+ | Algorithm: AES, HMAC, and SM4
Length: 256, 384, 512 | The derived key can be stored in the HUKS or directly returned in plaintext.| +| PBKDF2/SHA256
PBKDF2/SHA384
PBKDF2/SHA512 | 8+ | Algorithm: AES, HMAC, and SM4
Length: 256, 384, 512 | The derived key can be stored in the HUKS or directly returned in plaintext.| + +### Key Attestation + +| Algorithm                   |API Level| Remarks | +| ------------------ | :-----: | ------------------------------------------------------------ | +| RSA | 9+ | Only the keys using the PSS padding are supported. | +| ECC | 9+ | | +| X25519 | 9+ | | + +## Key Material Formats +HUKS defines a set of formats for the material of key pairs, public keys, and private keys of different cipher algorithms. + +### Key Pair Material +Key pair material = Key pair material header + Original key pair material + +The following uses the RSA key as an example. The application needs to apply for a Uint8Array and assign the variables to the corresponding positions based on the memory structure of the RSA key pair material. + +**Figure 1** Memory structure of the SRSA key material + +![huks_keymaterial_struct](figures/huks_keymaterial_struct.png) + +```ts +let rsa2048KeyPairMaterial = new Uint8Array([ + 0x01, 0x00, 0x00, 0x00, // Key algorithm: huks.HuksKeyAlg.HUKS_ALG_RSA = 1 + 0x00, 0x08, 0x00, 0x00, // Key size: 2048 bits + 0x00, 0x01, 0x00, 0x00, // Length of modulus n: 256 bytes + 0x03, 0x00, 0x00, 0x00, // Length of the public key exponent e: 3 bytes + 0x00, 0x01, 0x00, 0x00, // Length of the private key exponent d: 256 bytes + // Modulus n + 0xc5, 0x35, 0x62, 0x48, 0xc4, 0x92, 0x87, 0x73, 0x0d, 0x42, 0x96, 0xfc, 0x7b, 0x11, 0x05, 0x06, + 0x0f, 0x8d, 0x66, 0xc1, 0x0e, 0xad, 0x37, 0x44, 0x92, 0x95, 0x2f, 0x6a, 0x55, 0xba, 0xec, 0x1d, + 0x54, 0x62, 0x0a, 0x4b, 0xd3, 0xc7, 0x05, 0xe4, 0x07, 0x40, 0xd9, 0xb7, 0xc2, 0x12, 0xcb, 0x9a, + 0x90, 0xad, 0xe3, 0x24, 0xe8, 0x5e, 0xa6, 0xf8, 0xd0, 0x6e, 0xbc, 0xd1, 0x69, 0x7f, 0x6b, 0xe4, + 0x2b, 0x4e, 0x1a, 0x65, 0xbb, 0x73, 0x88, 0x6b, 0x7c, 0xaf, 0x7e, 0xd0, 0x47, 0x26, 0xeb, 0xa5, + 0xbe, 0xd6, 0xe8, 0xee, 0x9c, 0xa5, 0x66, 0xa5, 0xc9, 0xd3, 0x25, 0x13, 0xc4, 0x0e, 0x6c, 0xab, + 0x50, 0xb6, 0x50, 0xc9, 0xce, 0x8f, 0x0a, 0x0b, 0xc6, 0x28, 0x69, 0xe9, 0x83, 0x69, 0xde, 0x42, + 0x56, 0x79, 0x7f, 0xde, 0x86, 0x24, 0xca, 0xfc, 0xaa, 0xc0, 0xf3, 0xf3, 0x7f, 0x92, 0x8e, 0x8a, + 0x12, 0x52, 0xfe, 0x50, 0xb1, 0x5e, 0x8c, 0x01, 0xce, 0xfc, 0x7e, 0xf2, 0x4f, 0x5f, 0x03, 0xfe, + 0xa7, 0xcd, 0xa1, 0xfc, 0x94, 0x52, 0x00, 0x8b, 0x9b, 0x7f, 0x09, 0xab, 0xa8, 0xa4, 0xf5, 0xb4, + 0xa5, 0xaa, 0xfc, 0x72, 0xeb, 0x17, 0x40, 0xa9, 0xee, 0xbe, 0x8f, 0xc2, 0xd1, 0x80, 0xc2, 0x0d, + 0x44, 0xa9, 0x59, 0x44, 0x59, 0x81, 0x3b, 0x5d, 0x4a, 0xde, 0xfb, 0xae, 0x24, 0xfc, 0xa3, 0xd9, + 0xbc, 0x57, 0x55, 0xc2, 0x26, 0xbc, 0x19, 0xa7, 0x9a, 0xc5, 0x59, 0xa3, 0xee, 0x5a, 0xef, 0x41, + 0x80, 0x7d, 0xf8, 0x5e, 0xc1, 0x1d, 0x32, 0x38, 0x41, 0x5b, 0xb6, 0x92, 0xb8, 0xb7, 0x03, 0x0d, + 0x3e, 0x59, 0x0f, 0x1c, 0xb3, 0xe1, 0x2a, 0x95, 0x1a, 0x3b, 0x50, 0x4f, 0xc4, 0x1d, 0xcf, 0x73, + 0x7c, 0x14, 0xca, 0xe3, 0x0b, 0xa7, 0xc7, 0x1a, 0x41, 0x4a, 0xee, 0xbe, 0x1f, 0x43, 0xdd, 0xf9, + // Public key exponent e + 0x01, 0x00, 0x01, + // Private key exponent d + 0x88, 0x4b, 0x82, 0xe7, 0xe3, 0xe3, 0x99, 0x75, 0x6c, 0x9e, 0xaf, 0x17, 0x44, 0x3e, 0xd9, 0x07, + 0xfd, 0x4b, 0xae, 0xce, 0x92, 0xc4, 0x28, 0x44, 0x5e, 0x42, 0x79, 0x08, 0xb6, 0xc3, 0x7f, 0x58, + 0x2d, 0xef, 0xac, 0x4a, 0x07, 0xcd, 0xaf, 0x46, 0x8f, 0xb4, 0xc4, 0x43, 0xf9, 0xff, 0x5f, 0x74, + 0x2d, 0xb5, 0xe0, 0x1c, 0xab, 0xf4, 0x6e, 0xd5, 0xdb, 0xc8, 0x0c, 0xfb, 0x76, 0x3c, 0x38, 0x66, + 0xf3, 0x7f, 0x01, 0x43, 0x7a, 0x30, 0x39, 0x02, 0x80, 0xa4, 0x11, 0xb3, 0x04, 0xd9, 0xe3, 0x57, + 0x23, 0xf4, 0x07, 0xfc, 0x91, 0x8a, 0xc6, 0xcc, 0xa2, 0x16, 0x29, 0xb3, 0xe5, 0x76, 0x4a, 0xa8, + 0x84, 0x19, 0xdc, 0xef, 0xfc, 0xb0, 0x63, 0x33, 0x0b, 0xfa, 0xf6, 0x68, 0x0b, 0x08, 0xea, 0x31, + 0x52, 0xee, 0x99, 0xef, 0x43, 0x2a, 0xbe, 0x97, 0xad, 0xb3, 0xb9, 0x66, 0x7a, 0xae, 0xe1, 0x8f, + 0x57, 0x86, 0xe5, 0xfe, 0x14, 0x3c, 0x81, 0xd0, 0x64, 0xf8, 0x86, 0x1a, 0x0b, 0x40, 0x58, 0xc9, + 0x33, 0x49, 0xb8, 0x99, 0xc6, 0x2e, 0x94, 0x70, 0xee, 0x09, 0x88, 0xe1, 0x5c, 0x4e, 0x6c, 0x22, + 0x72, 0xa7, 0x2a, 0x21, 0xdd, 0xd7, 0x1d, 0xfc, 0x63, 0x15, 0x0b, 0xde, 0x06, 0x9c, 0xf3, 0x28, + 0xf3, 0xac, 0x4a, 0xa8, 0xb5, 0x50, 0xca, 0x9b, 0xcc, 0x0a, 0x04, 0xfe, 0x3f, 0x98, 0x68, 0x81, + 0xac, 0x24, 0x53, 0xea, 0x1f, 0x1c, 0x6e, 0x5e, 0xca, 0xe8, 0x31, 0x0d, 0x08, 0x12, 0xf3, 0x26, + 0xf8, 0x5e, 0xeb, 0x10, 0x27, 0xae, 0xaa, 0xc3, 0xad, 0x6c, 0xc1, 0x89, 0xdb, 0x7d, 0x5a, 0x12, + 0x55, 0xad, 0x11, 0x19, 0xa1, 0xa9, 0x8f, 0x0b, 0x6d, 0x78, 0x8d, 0x1c, 0xdf, 0xe5, 0x63, 0x82, + 0x0b, 0x7d, 0x23, 0x04, 0xb4, 0x75, 0x8c, 0xed, 0x77, 0xfc, 0x1a, 0x85, 0x29, 0x11, 0xe0, 0x61, + ]); +``` + +The key algorithm is a value of [HuksKeyAlg](../reference/apis/js-apis-huks.md#hukskeyalg). + +- **RSA Key Pair Material Format** + | Key Algorithm| Key Size| Modulus n Length Ln| Public Key Exponent e Length Le | Private Key Exponent d Length Ld| n | e | d | + | :----: |:----:|:----:|:----:|:----:|:----:|:----:|:----:| + |4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|Ln bytes|Le bytes|Ld bytes| + + +- **ECC Key Pair Material Format** + | Key Algorithm| Key Size| Coordinate x Length Lx| Coordinate y Length Ly| Coordinate z Length Lz| x | y | z | + | :----: |:----:|:----:|:----:|:----:|:----:|:----:|:----:| + |4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|Lx bytes|Ly bytes|Lz bytes| + + +- **DSA Key Pair Material Format** + | Key Algorithm| Key Size| Private Key x Length Lx| Public Key y Length Ly| Prime p Length Lp| Prime Factor q Length Lq| g length Lg| x | y | p | q | g | + | :----: |:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:| + |4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|Lx bytes|Ly bytes|Lp bytes|Lq bytes|Lg bytes| + + +- **DH Key Pair Material Format** + | Key Algorithm| Key Size| Public Key pk Length Lpk| Private Key sk Length Lsk| Reserved Field| pk | sk | + |:----:|:----:|:----:|:----:|:----:|:----:|:----:| + |4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|Lpk bytes|Lsk bytes| + + +- **Curve25519 Key Pair Material Format** + | Key Algorithm| Key Size| Public Key pk Length Lpk| Private Key sk Length Lsk| Reserved Field| pk | sk | + |:----:|:----:|:----:|:----:|:----:|:----:|:----:| + |4 bytes|4 bytes|4 bytes|4 bytes|4 bytes|Lpk bytes|Lsk bytes| + + +### Public Key Material + +When a public key is exported or imported, the key material is encapsulated in the DER format defined in X.509. + +The following is ECC public key in EDR format: +```ts +let eccP256PubKey = new Uint8Array([ + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xc0, 0xfe, 0x1c, 0x67, 0xde, + 0x86, 0x0e, 0xfb, 0xaf, 0xb5, 0x85, 0x52, 0xb4, 0x0e, 0x1f, 0x6c, 0x6c, 0xaa, 0xc5, 0xd9, 0xd2, + 0x4d, 0xb0, 0x8a, 0x72, 0x24, 0xa1, 0x99, 0xaf, 0xfc, 0x3e, 0x55, 0x5a, 0xac, 0x99, 0x3d, 0xe8, + 0x34, 0x72, 0xb9, 0x47, 0x9c, 0xa6, 0xd8, 0xfb, 0x00, 0xa0, 0x1f, 0x9f, 0x7a, 0x41, 0xe5, 0x44, + 0x3e, 0xb2, 0x76, 0x08, 0xa2, 0xbd, 0xe9, 0x41, 0xd5, 0x2b, 0x9e]); +``` + +### Private Key Material + +The private key material is in the same format as the key pair material. When the private key material is encapsulated, the public key length in the header of the key pair material is set to 0 and original key pair material and the private key material are combined. + +Private key material = Header of the key pair material + Original private key material + +The following uses the RSA private key material as an example: + +![huks_keymaterial_rsa_priv_struct](figures/huks_keymaterial_rsa_priv_struct.png) + +```ts +let rsa2048PrivateKeyMaterial = new Uint8Array([ + 0x01, 0x00, 0x00, 0x00, // Key algorithm: huks.HuksKeyAlg.HUKS_ALG_RSA = 1 + 0x00, 0x08, 0x00, 0x00, // Key size: 2048 bits + 0x00, 0x01, 0x00, 0x00, // Length of modulus n: 256 byptes + 0x00, 0x00, 0x00, 0x00, // Length of the public key exponent e: 0 + 0x00, 0x01, 0x00, 0x00, // Length of the private key exponent d: 256 bytes + // Modulus n + 0xc5, 0x35, 0x62, 0x48, 0xc4, 0x92, 0x87, 0x73, 0x0d, 0x42, 0x96, 0xfc, 0x7b, 0x11, 0x05, 0x06, + 0x0f, 0x8d, 0x66, 0xc1, 0x0e, 0xad, 0x37, 0x44, 0x92, 0x95, 0x2f, 0x6a, 0x55, 0xba, 0xec, 0x1d, + 0x54, 0x62, 0x0a, 0x4b, 0xd3, 0xc7, 0x05, 0xe4, 0x07, 0x40, 0xd9, 0xb7, 0xc2, 0x12, 0xcb, 0x9a, + 0x90, 0xad, 0xe3, 0x24, 0xe8, 0x5e, 0xa6, 0xf8, 0xd0, 0x6e, 0xbc, 0xd1, 0x69, 0x7f, 0x6b, 0xe4, + 0x2b, 0x4e, 0x1a, 0x65, 0xbb, 0x73, 0x88, 0x6b, 0x7c, 0xaf, 0x7e, 0xd0, 0x47, 0x26, 0xeb, 0xa5, + 0xbe, 0xd6, 0xe8, 0xee, 0x9c, 0xa5, 0x66, 0xa5, 0xc9, 0xd3, 0x25, 0x13, 0xc4, 0x0e, 0x6c, 0xab, + 0x50, 0xb6, 0x50, 0xc9, 0xce, 0x8f, 0x0a, 0x0b, 0xc6, 0x28, 0x69, 0xe9, 0x83, 0x69, 0xde, 0x42, + 0x56, 0x79, 0x7f, 0xde, 0x86, 0x24, 0xca, 0xfc, 0xaa, 0xc0, 0xf3, 0xf3, 0x7f, 0x92, 0x8e, 0x8a, + 0x12, 0x52, 0xfe, 0x50, 0xb1, 0x5e, 0x8c, 0x01, 0xce, 0xfc, 0x7e, 0xf2, 0x4f, 0x5f, 0x03, 0xfe, + 0xa7, 0xcd, 0xa1, 0xfc, 0x94, 0x52, 0x00, 0x8b, 0x9b, 0x7f, 0x09, 0xab, 0xa8, 0xa4, 0xf5, 0xb4, + 0xa5, 0xaa, 0xfc, 0x72, 0xeb, 0x17, 0x40, 0xa9, 0xee, 0xbe, 0x8f, 0xc2, 0xd1, 0x80, 0xc2, 0x0d, + 0x44, 0xa9, 0x59, 0x44, 0x59, 0x81, 0x3b, 0x5d, 0x4a, 0xde, 0xfb, 0xae, 0x24, 0xfc, 0xa3, 0xd9, + 0xbc, 0x57, 0x55, 0xc2, 0x26, 0xbc, 0x19, 0xa7, 0x9a, 0xc5, 0x59, 0xa3, 0xee, 0x5a, 0xef, 0x41, + 0x80, 0x7d, 0xf8, 0x5e, 0xc1, 0x1d, 0x32, 0x38, 0x41, 0x5b, 0xb6, 0x92, 0xb8, 0xb7, 0x03, 0x0d, + 0x3e, 0x59, 0x0f, 0x1c, 0xb3, 0xe1, 0x2a, 0x95, 0x1a, 0x3b, 0x50, 0x4f, 0xc4, 0x1d, 0xcf, 0x73, + 0x7c, 0x14, 0xca, 0xe3, 0x0b, 0xa7, 0xc7, 0x1a, 0x41, 0x4a, 0xee, 0xbe, 0x1f, 0x43, 0xdd, 0xf9, + // Private key exponent d + 0x88, 0x4b, 0x82, 0xe7, 0xe3, 0xe3, 0x99, 0x75, 0x6c, 0x9e, 0xaf, 0x17, 0x44, 0x3e, 0xd9, 0x07, + 0xfd, 0x4b, 0xae, 0xce, 0x92, 0xc4, 0x28, 0x44, 0x5e, 0x42, 0x79, 0x08, 0xb6, 0xc3, 0x7f, 0x58, + 0x2d, 0xef, 0xac, 0x4a, 0x07, 0xcd, 0xaf, 0x46, 0x8f, 0xb4, 0xc4, 0x43, 0xf9, 0xff, 0x5f, 0x74, + 0x2d, 0xb5, 0xe0, 0x1c, 0xab, 0xf4, 0x6e, 0xd5, 0xdb, 0xc8, 0x0c, 0xfb, 0x76, 0x3c, 0x38, 0x66, + 0xf3, 0x7f, 0x01, 0x43, 0x7a, 0x30, 0x39, 0x02, 0x80, 0xa4, 0x11, 0xb3, 0x04, 0xd9, 0xe3, 0x57, + 0x23, 0xf4, 0x07, 0xfc, 0x91, 0x8a, 0xc6, 0xcc, 0xa2, 0x16, 0x29, 0xb3, 0xe5, 0x76, 0x4a, 0xa8, + 0x84, 0x19, 0xdc, 0xef, 0xfc, 0xb0, 0x63, 0x33, 0x0b, 0xfa, 0xf6, 0x68, 0x0b, 0x08, 0xea, 0x31, + 0x52, 0xee, 0x99, 0xef, 0x43, 0x2a, 0xbe, 0x97, 0xad, 0xb3, 0xb9, 0x66, 0x7a, 0xae, 0xe1, 0x8f, + 0x57, 0x86, 0xe5, 0xfe, 0x14, 0x3c, 0x81, 0xd0, 0x64, 0xf8, 0x86, 0x1a, 0x0b, 0x40, 0x58, 0xc9, + 0x33, 0x49, 0xb8, 0x99, 0xc6, 0x2e, 0x94, 0x70, 0xee, 0x09, 0x88, 0xe1, 0x5c, 0x4e, 0x6c, 0x22, + 0x72, 0xa7, 0x2a, 0x21, 0xdd, 0xd7, 0x1d, 0xfc, 0x63, 0x15, 0x0b, 0xde, 0x06, 0x9c, 0xf3, 0x28, + 0xf3, 0xac, 0x4a, 0xa8, 0xb5, 0x50, 0xca, 0x9b, 0xcc, 0x0a, 0x04, 0xfe, 0x3f, 0x98, 0x68, 0x81, + 0xac, 0x24, 0x53, 0xea, 0x1f, 0x1c, 0x6e, 0x5e, 0xca, 0xe8, 0x31, 0x0d, 0x08, 0x12, 0xf3, 0x26, + 0xf8, 0x5e, 0xeb, 0x10, 0x27, 0xae, 0xaa, 0xc3, 0xad, 0x6c, 0xc1, 0x89, 0xdb, 0x7d, 0x5a, 0x12, + 0x55, 0xad, 0x11, 0x19, 0xa1, 0xa9, 0x8f, 0x0b, 0x6d, 0x78, 0x8d, 0x1c, 0xdf, 0xe5, 0x63, 0x82, + 0x0b, 0x7d, 0x23, 0x04, 0xb4, 0x75, 0x8c, 0xed, 0x77, 0xfc, 0x1a, 0x85, 0x29, 0x11, 0xe0, 0x61, + ]); +``` diff --git a/en/application-dev/security/huks-guidelines.md b/en/application-dev/security/huks-guidelines.md index b72be28c24888642d1220779104477d28a170176..3b40ab0af97c390f6026b26abf501dede5156aef 100644 --- a/en/application-dev/security/huks-guidelines.md +++ b/en/application-dev/security/huks-guidelines.md @@ -1,186 +1,359 @@ + # HUKS Development -OpenHarmony Universal KeyStore (HUKS) provides KeyStore (KS) capabilities for applications, including key management and key cryptography operations. HUKS also provides APIs for applications to import or generate keys. +## Key Generation + +The HUKS provides the capability of randomly generating keys for services. For a key generated by the HUKS, its plaintext will never be exposed outside throughout the lifecycle. This ensures that no one can access the plaintext of the key. Even the service that generates the key can call APIs provided by the HUKS to perform key operations and obtain the operation result, rather than accessing the key. + +**How to Develop** + +Use [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**, a key attribute set in **options**, and **callback** to result the result asynchronously. For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). + +1. Determine the key alias. +2. Initialize the key attributes.
Use [HuksParam](../reference/apis/js-apis-huks.md#huksparam) to encapsulate key attributes. 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. +3. Pass in the key alias and key parameter set to generate a key. > **NOTE** > -> This document is based on API version 9 and applies only to ArkTS development. - -### **Prerequisites** +> The key alias cannot exceed 64 bytes. -The HUKS module must have been imported. +**Sample code** ```ts -import huks from '@ohos.security.huks' +/* + * Generate a DH key and return the result by a callback. + */ +import huks from '@ohos.security.huks'; + +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let keyAlias = 'dh_key'; +let 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_2048 +} +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 +} +let huksOptions = { + properties: properties, + inData: new Uint8Array(new Array()) +} + +/* + * Generate a key. + */ +function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) { + return new Promise((resolve, reject) => { + try { + huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throw (error); + } + }); +} + +async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { + console.info(`enter callback generateKeyItem`); + try { + await generateKeyItem(keyAlias, huksOptions) + .then((data) => { + console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + }); + } catch (error) { + console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + } +} + + +async function TestGenKey() { + await publicGenKeyFunc(keyAlias, huksOptions); +} ``` -### Generating a Key +## Key Import +If the key is generated outside the HUKS (for example, generated through key agreement or by a server), the application can import the key to the HUKS for management. The HUKS supports import of keys in plaintext. However, if keys are imported in plaintext, the keys are exposed in the REE memory. This operation applies to lightweight devices or security-insensitive services. For security-sensitive services, use the secure import provided by the HUKS. Secure import allows the keys generate keys by services to be transferred to the HUKS through an end-to-end encrypted transmission channel. + +Once a key is imported to the HUKS, its plaintext will not be exposed outside the HUKS throughout the lifecycle of the key. -Generate a key for an application by specifying the alias and key parameters. -> **NOTE** -> -> - When a key is used if the parameters passed in does not comply with the parameters passed in during the key generation, the parameter verification will fail. -> -> - If an optional parameter required by the algorithm is not passed in during the key generation process, it must be passed in when the key is used. -**Supported Key Types** +### Importing a Key in Plaintext -The following lists the mandatory parameters for key generation, including the key algorithm, key length, and key usage. -| HUKS_ALG_ALGORITHM | HUKS_ALG_KEY_SIZE | HUKS_ALG_PURPOSE | -| ------------------ | :----------------------------------------------------------- | ------------------------------------------------------------ | -| HUKS_ALG_RSA | HUKS_RSA_KEY_SIZE_512 HUKS_RSA_KEY_SIZE_768 HUKS_RSA_KEY_SIZE_1024 HUKS_RSA_KEY_SIZE_2048 HUKS_RSA_KEY_SIZE_3072 HUKS_RSA_KEY_SIZE_4096 | HUKS_KEY_PURPOSE_ENCRYPT HUKS_KEY_PURPOSE_DECRYPT HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | -| HUKS_ALG_AES | HUKS_AES_KEY_SIZE_128 HUKS_AES_KEY_SIZE_192 HUKS_AES_KEY_SIZE_256 | HUKS_KEY_PURPOSE_ENCRYPT HUKS_KEY_PURPOSE_DECRYPT HUKS_KEY_PURPOSE_DERIVE | -| HUKS_ALG_ECC | HUKS_ECC_KEY_SIZE_224, HUKS_ECC_KEY_SIZE_256, HUKS_ECC_KEY_SIZE_384, HUKS_ECC_KEY_SIZE_521| HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | -| HUKS_ALG_X25519 | HUKS_CURVE25519_KEY_SIZE_256 | HUKS_KEY_PURPOSE_AGREE | -| HUKS_ALG_ED25519 | HUKS_CURVE25519_KEY_SIZE_256 | HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | -| HUKS_ALG_DSA | HUKS_RSA_KEY_SIZE_1024 | HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | -| HUKS_ALG_DH | HUKS_DH_KEY_SIZE_2048, HUKS_DH_KEY_SIZE_3072, HUKS_DH_KEY_SIZE_4096| HUKS_KEY_PURPOSE_AGREE | -| HUKS_ALG_ECDH | HUKS_ECC_KEY_SIZE_224, HUKS_ECC_KEY_SIZE_256, HUKS_ECC_KEY_SIZE_384, HUKS_ECC_KEY_SIZE_521| HUKS_KEY_PURPOSE_AGREE | -| HUKS_ALG_SM2 | HUKS_SM2_KEY_SIZE_256 | HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | -| HUKS_ALG_SM4 | HUKS_SM4_KEY_SIZE_128 | HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT | +Use [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 attribute set in **options**, and **callback** to return the result asynchronously. For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). -Before you get started, understand the following variables: -| Parameter | Type | Mandatory| Description | -| ---------------- | ----------- | ---- | ------------------------------------------------------------ | -| genKeyAlias | string | Yes | Alias of the key generated. | -| genKeyProperties | HuksOptions | Yes | Tags required for generating the key. The key algorithm, key usage, and key length are mandatory.| +1. Determine the key alias. +2. Encapsulate the key material and key attribute set.
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 form. Encapsulate key attributes in [HuksParam](../reference/apis/js-apis-huks.md#huksparam), and use a **HuksParam** array to assign values to the **properties** field. The key attribute set 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). +3. Import the key. + -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). + +**Sample code** ```ts -/* Generate an ECC key of 256 bits. */ -let keyAlias = 'keyAlias'; +/* + /* Import an AES key of 256 bits. */ + */ + +/* Key */ +let plainTextSize32 = new Uint8Array([ + 0xfb, 0x8b, 0x9f, 0x12, 0xa0, 0x83, 0x19, 0xbe, 0x6a, 0x6f, 0x63, 0x2a, 0x7c, 0x86, 0xba, 0xca, + 0x64, 0x0b, 0x88, 0x96, 0xe2, 0xfa, 0x77, 0xbc, 0x71, 0xe3, 0x0f, 0x0f, 0x9e, 0x3c, 0xe5, 0xf9 +]); + +/* + * Determine the key alias. + */ +let keyAlias = 'AES256Alias_sample'; + +/* + * Encapsulate the key attribute set and key material. + */ let properties = new Array(); -// Mandatory parameter. properties[0] = { tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_ECC + value: huks.HuksKeyAlg.HUKS_ALG_AES }; -// Mandatory parameter. properties[1] = { tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256 + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 }; -// Mandatory parameter. properties[2] = { tag: huks.HuksTag.HUKS_TAG_PURPOSE, value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY -}; -// Optional parameter. -properties[3] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT }; let options = { - properties: properties + properties: properties, + inData: plainTextSize32 }; + +/* + * Import the key. + */ try { - huks.generateKeyItem(keyAlias, options, function (error, data) { + huks.importKeyItem(keyAlias, options, function (error, data) { if (error) { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: importKeyItem failed, code: ${error.code}, msg: ${error.message}`); } else { - console.info(`callback: generateKeyItem key success`); + console.info(`callback: importKeyItem success`); } }); } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: importKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); +} +``` + +**Verification** + +Check whether the key exists. If yes, the key is imported successfully. + +**Sample code** + +```ts +import huks from '@ohos.security.huks'; + +let keyAlias = 'AES256Alias_sample'; +let isKeyExist; + +let keyProperties = new Array(); +keyProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES, +} +let huksOptions = { + properties: keyProperties, // It cannot be empty. + inData: new Uint8Array(new Array()) // It cannot be empty. +} +try { + huks.isKeyItemExist(keyAlias, huksOptions, function (error, data) { + if (error) { + console.error(`callback: isKeyItemExist failed, code: ${error.code}, msg: ${error.message}`); + } else { + if (data !== null && data.valueOf() !== null) { + isKeyExist = data.valueOf(); + console.info(`callback: isKeyItemExist success, isKeyExist = ${isKeyExist}`); + } + } + }); +} catch (error) { + console.error(`callback: isKeyItemExist input arg invalid, code: ${error.code}, msg: ${error.message}`); } ``` +### Importing a Wrapped Key +Compared with import of plaintext, secure import has complex key material and operations. The following figure illustrates the development process of secure import. -### Key Import and Export -The **HUKS** module allows the public key of its own asymmetric key (public and private key pair) to be exported based on the key alias. -The **HUKS** module also supports import of external keys. Except the public keys of asymmetric keys, the keys imported into the HUKS cannot be exported in their lifecycle. If the alias of the key to be imported already exists in HUKS, the newly imported key will overwrite the existing one. +**Figure 1** Development process of secure import -The development procedure is as follows: +![huks_import_wrapped_key](figures/huks_import_wrapped_key.png) -1. Generate a key. -2. Export the key. -3. Import the key. -**Supported Types of Keys to Import** -AES128, AES192, AES256, RSA512, RSA768, RSA1024, RSA2048, RSA3072, RSA4096, HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512, ECC224, ECC256, ECC384, ECC521, Curve25519, DSA, SM2, SM3, SM4 -**Supported Types of Keys to Export** +**Available APIs** -RSA512, RSA768, RSA1024, RSA2048, RSA3072, RSA4096, ECC224, ECC256, ECC384, ECC521, Curve25519, DSA, SM2 +You need to use the APIs for generating a key, exporting a public key, importing a wrapped key, and deleting a key in sequence. -> **NOTE**
-> -> The key alias cannot exceed 64 bytes. +**Table 1** APIs for secure import + +| API | Description | +| -------------------------------------- | ----------------------------| +|generateKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback\) : void| Generates a key.| +|exportKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback) : void| Exports the public key of a key pair.| +|importWrappedKeyItem(keyAlias: string, wrappingKeyAlias: string, options: HuksOptions, callback: AsyncCallback) : void|Imports a wrapped key.| +|deleteKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback) : void|Deletes a key.| + +>**NOTE**
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 **LengthData-Data** format. Specifically, the application needs to apply for a Uint8Array and encapsulate the Uint8Array in the sequence listed in the following table. -Before you get started, understand the following variables: +**Table 2** Format of the wrapped key material -| Parameter | Type | Mandatory| Description | -| -------------- | ----------- | ---- | ------------------------ | -| exportKeyAlias | string | Yes | Alias of the key to generate. | -| importKeyAlias | string | Yes | Alias of the key to import. | -| huksOptions | HuksOptions | Yes | Tags required for generating the key.| -| encryptOptions | HuksOptions | Yes | Tags required for importing the key.| +| Content| Public Key Length (Lpk2)| Public Key pk2| k2 AAD2 Length LAAD2| k2 Encryption Parameter AAD2| k2 Nonce2 Length LNonce2| k2 Encryption Parameter Nonce2| +| :--: |:----:|:----: |:----: | :----: | :----:|:----:| +|Length| 4 bytes|Lpk2 bytes| 4 bytes| LAAD2 bytes| 4 bytes| LNonce2 bytes| +| Content| k2 AEAD2 Length LAEAD2| k2 Encryption Parameter AEAD2| k3 Ciphertext Length Lk3_enc| k3 Ciphertext k3_enc| k3 AAD3 Length LAAD3| k3 Encryption Parameter AAD3| +|Length| 4 bytes|LAEAD2 bytes| 4 bytes| Lk3_enc bytes| 4 bytes| LAAD3 bytes| +| Content| k3 Nonce3 Length LNonce3| k3 Encryption Parameter Nonce3| k3 AEAD3 Length LAEAD3| k3 Encryption Parameter AEAD3| Length of **k1'_size** Lk1'_size| Key Plaintext Material Length k1'_size| +|Length| 4 bytes|LNonce3 bytes| 4 bytes| LAEAD3 bytes| 4 bytes| Lk1'_size bytes| +|Content|k1' Ciphertext Length Lk1'_enc| k1' ciphertext k1'_enc| | | | | +|Length| 4 bytes|Lk1'_enc bytes| | | | | -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). +**How to Develop** -**Example** +The following example provides the development involving HUKS APIs (using the ECDH key agreement suite). The operations performed by the service are not included. +1. Convert the key material to the HUKS format. +2. Generate a wrapping key (a key used for secure import). +3. Export the public key material. +4. Wrap the key material to be imported. +5. Import the wrapped key material. +6. Delete the wrapping key. + +**Sample code** ```ts -/* Export an RSA512 key and import DH2048, RSA512, x25519, and ECC256 keys.*/ +/* + * Import an SM2 key and return the result by a callback. + */ import huks from '@ohos.security.huks'; -function StringToUint8Array(str) { - let arr = []; - for (let i = 0, j = str.length; i < j; ++i) { - arr.push(str.charCodeAt(i)); - } - return new Uint8Array(arr); -} +/* + * Determine the key alias. + */ +let importAlias = "importAlias"; +let wrapAlias = "wrappingKeyAlias"; +let exportKey; -function Uint8ArrayToString(fileData) { - let dataString = ''; - for (let i = 0; i < fileData.length; i++) { - dataString += String.fromCharCode(fileData[i]); - } - return dataString; -} +/* + * Convert the key material into a HUKS ECC-P-256 key pair for secure import. + */ +let inputEccPair = new Uint8Array([ + 0x02, 0x00, 0x00, 0x00, // key algorithm: huks.HuksKeyAlg.HUKS_ALG_ECC = 2 + 0x00, 0x01, 0x00, 0x00, // key size: 256 bits + 0x20, 0x00, 0x00, 0x00, // Coordinate x length: 32 bytes + 0x20, 0x00, 0x00, 0x00, // Coordinate y length: 32 bytes + 0x20, 0x00, 0x00, 0x00, // Coordinate z length: 32 bytes + // Coordinate x + 0xa5, 0xb8, 0xa3, 0x78, 0x1d, 0x6d, 0x76, 0xe0, 0xb3, 0xf5, 0x6f, 0x43, 0x9d, 0xcf, 0x60, 0xf6, + 0x0b, 0x3f, 0x64, 0x45, 0xa8, 0x3f, 0x1a, 0x96, 0xf1, 0xa1, 0xa4, 0x5d, 0x3e, 0x2c, 0x3f, 0x13, + // Coordinate y + 0xd7, 0x81, 0xf7, 0x2a, 0xb5, 0x8d, 0x19, 0x3d, 0x9b, 0x96, 0xc7, 0x6a, 0x10, 0xf0, 0xaa, 0xbc, + 0x91, 0x6f, 0x4d, 0xa7, 0x09, 0xb3, 0x57, 0x88, 0x19, 0x6f, 0x00, 0x4b, 0xad, 0xee, 0x34, 0x35, + // Coordinate z + 0xfb, 0x8b, 0x9f, 0x12, 0xa0, 0x83, 0x19, 0xbe, 0x6a, 0x6f, 0x63, 0x2a, 0x7c, 0x86, 0xba, 0xca, + 0x64, 0x0b, 0x88, 0x96, 0xe2, 0xfa, 0x77, 0xbc, 0x71, 0xe3, 0x0f, 0x0f, 0x9e, 0x3c, 0xe5, 0xf9 + ]); -function Uint32ToUint8(value) { - let arr = new Uint8Array(4 * value.length); - for (let i = 0, j = value.length; i < j; i++) { - arr[i * 4+3] = (value[i] >> 24) & 0xFF; - arr[i * 4+2] = (value[i] >> 16) & 0xFF; - arr[i * 4+1] = (value[i] >> 8) & 0xFF; - arr[i*4] = (value[i]) & 0xFF; - } - return arr; -} +/* + * Encapsulate the key attribute set. + */ +// Attribute set for the wrapping key. +let 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_256 +}; +properties[2] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_UNWRAP +}; +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 +}; +properties[4] = { + tag: huks.HuksTag.HUKS_TAG_IMPORT_KEY_TYPE, + value: huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR, +}; +let huksOptions = { + properties: properties, + inData: inputEccPair +}; -async function publicGenKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); - try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} +// Attribute set of the AES256 key to be imported. +let importProperties = new Array(); +importProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES +}; +importProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 +}; +importProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT +}; +importProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC +}; +importProperties[4] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE +}; +importProperties[5] = { + tag: huks.HuksTag.HUKS_TAG_UNWRAP_ALGORITHM_SUITE, + value: huks.HuksUnwrapSuite.HUKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING // Use the ECDH+AES256GCM suite. +}; +let importOptions = { + properties: importProperties, + inData: new Uint8Array(new Array()) +}; -function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) { +// Export the public key of the key pair. +function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -188,92 +361,96 @@ function generateKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) { } }); } catch (error) { - throw (error); + throwObject.isThrow = true; + throw(error); } }); } -async function publicExportKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { +async function publicExportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { console.info(`enter callback export`); + let throwObject = {isThrow: false}; try { - await exportKeyItem(keyAlias, huksOptions) - .then((data) => { + await exportKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); + exportKey = data.outData; }) .catch(error => { - console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: exportKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function exportKeyItem(keyAlias: string, huksOptions: huks.HuksOptions): Promise { +// Generate a wrapping key (the key is imported here). +function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { - huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { + huks.importKeyItem(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); - } else { + } else { resolve(data); } }); } catch (error) { - throw (error); + throwObject.isThrow = true; + throw(error); } }); } -async function publicImportKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { +async function publicImportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { console.info(`enter promise importKeyItem`); + let throwObject = {isThrow: false}; try { - await importKeyItem(keyAlias, huksOptions) - .then((data) => { + await importKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { console.info(`callback: importKeyItem success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: importKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: importKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: importKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function importKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.importKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw (error); - } - }); -} - -async function publicDeleteKeyFunc(keyAlias: string, huksOptions: huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); +// Perform secure import. +async function publicImportWrappedKey(keyAlias:string, wrappingKeyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback importWrappedKeyItem`); + var throwObject = {isThrow: false}; try { - await deleteKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + await importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: importWrappedKeyItem success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: importWrappedKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: importWrappedKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) { +function importWrappedKeyItem(keyAlias:string, wrappingKeyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { + huks.importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -281,549 +458,332 @@ function deleteKeyItem(keyAlias: string, huksOptions: huks.HuksOptions) { } }); } catch (error) { - throw (error); + throwObject.isThrow = true; + throw(error); } }); } -// Export the RSA key. -async function testExportRsa() { - let exportKeyAlias = 'export_rsa_key'; - /* Configure the parameters for generating the key. */ - let exportProperties = new Array(); - exportProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_RSA - } - exportProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT - } - exportProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_512 - } - exportProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_ECB - } - exportProperties[4] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_PKCS1_V1_5 - } - exportProperties[5] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - } - let huksOptions = { - properties: exportProperties, - inData: new Uint8Array(new Array()) +// Delete the wrapping key. +function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { + return new Promise((resolve, reject) => { + try { + huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); +} + +async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback deleteKeyItem`); + let throwObject = {isThrow: false}; + try { + await deleteKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: deletKeeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } +} - /* Generate a key. */ - await publicGenKeyFunc(exportKeyAlias, huksOptions); +async function ImportWrappedKeyNormalTest() { + console.info(`enter ImportWrapKey test`); + /* + * Generate a wrapping key (the key is imported here). + */ + await publicImportKeyFunc(wrapAlias, huksOptions); - /* Export the key. */ - await publicExportKeyFunc(exportKeyAlias, huksOptions); - await publicDeleteKeyFunc(exportKeyAlias, huksOptions); -} - -// DH key -let g_dhPubData = new Uint8Array([ - 0x8a, 0xbf, 0x16, 0x67, 0x1b, 0x92, 0x4b, 0xf2, 0xe0, 0x02, 0xc5, 0x1f, 0x84, 0x00, 0xf8, 0x93, - 0x0f, 0x74, 0xe7, 0x0f, 0xba, 0x78, 0x30, 0xa8, 0x2d, 0x92, 0xef, 0x9b, 0x80, 0xeb, 0x76, 0xea, - 0x26, 0x74, 0x72, 0x63, 0x6a, 0x27, 0xc3, 0x8f, 0xcf, 0xbe, 0x82, 0xa2, 0x8b, 0xdc, 0x65, 0x58, - 0xe3, 0xff, 0x29, 0x97, 0xad, 0xb3, 0x4a, 0x2c, 0x50, 0x08, 0xb5, 0x68, 0xe1, 0x90, 0x5a, 0xdc, - 0x48, 0xb3, 0x6b, 0x7a, 0xce, 0x2e, 0x81, 0x3d, 0x38, 0x35, 0x59, 0xdc, 0x39, 0x8a, 0x97, 0xfe, - 0x20, 0x86, 0x20, 0xdb, 0x55, 0x38, 0x23, 0xca, 0xb5, 0x5b, 0x61, 0x00, 0xdc, 0x45, 0xe2, 0xa1, - 0xf4, 0x1e, 0x7b, 0x01, 0x7a, 0x84, 0x36, 0xa4, 0xa8, 0x1c, 0x0d, 0x3d, 0xde, 0x57, 0x66, 0x73, - 0x4e, 0xaf, 0xee, 0xb0, 0xb0, 0x69, 0x0c, 0x13, 0xba, 0x76, 0xff, 0x2e, 0xb6, 0x16, 0xf9, 0xfc, - 0xd6, 0x09, 0x5b, 0xc7, 0x37, 0x65, 0x84, 0xd5, 0x82, 0x8a, 0xd7, 0x5b, 0x57, 0xe3, 0x0e, 0x89, - 0xbe, 0x05, 0x05, 0x55, 0x2e, 0x9f, 0x94, 0x8a, 0x53, 0xdc, 0xb7, 0x00, 0xb2, 0x6a, 0x7b, 0x8e, - 0xdf, 0x6e, 0xa4, 0x6d, 0x13, 0xb6, 0xbc, 0xaa, 0x8e, 0x44, 0x11, 0x50, 0x32, 0x91, 0x56, 0xa2, - 0x22, 0x3f, 0x2f, 0x08, 0xbb, 0x4d, 0xbb, 0x69, 0xe6, 0xb1, 0xc2, 0x70, 0x79, 0x15, 0x54, 0xad, - 0x4a, 0x29, 0xef, 0xa9, 0x3e, 0x64, 0x8d, 0xf1, 0x90, 0xf4, 0xa7, 0x93, 0x8c, 0x7a, 0x02, 0x4d, - 0x38, 0x1f, 0x58, 0xb8, 0xe4, 0x7c, 0xe1, 0x66, 0x1c, 0x72, 0x30, 0xf3, 0x4c, 0xf4, 0x24, 0xd1, - 0x2d, 0xb7, 0xf1, 0x5a, 0x0f, 0xb8, 0x20, 0xc5, 0x90, 0xe5, 0xca, 0x45, 0x84, 0x5c, 0x08, 0x08, - 0xbf, 0xf9, 0x69, 0x41, 0xf5, 0x49, 0x85, 0x31, 0x35, 0x14, 0x69, 0x12, 0x57, 0x9c, 0xc8, 0xb7]); -let g_dhPriData = new Uint8Array([ - 0x01, 0xbc, 0xa7, 0x42, 0x25, 0x79, 0xc5, 0xaf, 0x0f, 0x9c, 0xde, 0x00, 0x3b, 0x58, 0x5c, 0xd1, - 0x1d, 0x7b, 0xcf, 0x66, 0xcd, 0xa9, 0x10, 0xae, 0x92, 0x2d, 0x3c, 0xb7, 0xf3]); -let g_dhX509PubData = new Uint8Array([ - 0x30, 0x82, 0x02, 0x29, 0x30, 0x82, 0x01, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, - 0x01, 0x03, 0x01, 0x30, 0x82, 0x01, 0x0c, 0x02, 0x82, 0x01, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, 0x9a, 0xaf, 0xdc, 0x56, 0x20, - 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, - 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, 0x9b, 0x3e, 0xf9, 0x7d, 0x2f, 0xe3, 0x63, - 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, - 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, - 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, 0x98, 0x4f, 0x0c, 0x70, - 0xe0, 0xe6, 0x8b, 0x77, 0xe2, 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, - 0x36, 0xad, 0xe7, 0x35, 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, - 0xb3, 0x24, 0xfb, 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, 0xb9, 0x6a, 0xda, 0xb7, - 0x60, 0xd7, 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, - 0x63, 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, 0x91, 0x72, 0xfe, 0x9c, - 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, 0x3b, 0x1b, - 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, 0x8e, 0xf1, 0x83, - 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, 0x88, 0x6b, 0x42, 0x38, - 0x61, 0x28, 0x5c, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0x01, 0x02, 0x02, - 0x02, 0x00, 0xe1, 0x03, 0x82, 0x01, 0x06, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0x8a, 0xbf, 0x16, - 0x67, 0x1b, 0x92, 0x4b, 0xf2, 0xe0, 0x02, 0xc5, 0x1f, 0x84, 0x00, 0xf8, 0x93, 0x0f, 0x74, 0xe7, - 0x0f, 0xba, 0x78, 0x30, 0xa8, 0x2d, 0x92, 0xef, 0x9b, 0x80, 0xeb, 0x76, 0xea, 0x26, 0x74, 0x72, - 0x63, 0x6a, 0x27, 0xc3, 0x8f, 0xcf, 0xbe, 0x82, 0xa2, 0x8b, 0xdc, 0x65, 0x58, 0xe3, 0xff, 0x29, - 0x97, 0xad, 0xb3, 0x4a, 0x2c, 0x50, 0x08, 0xb5, 0x68, 0xe1, 0x90, 0x5a, 0xdc, 0x48, 0xb3, 0x6b, - 0x7a, 0xce, 0x2e, 0x81, 0x3d, 0x38, 0x35, 0x59, 0xdc, 0x39, 0x8a, 0x97, 0xfe, 0x20, 0x86, 0x20, - 0xdb, 0x55, 0x38, 0x23, 0xca, 0xb5, 0x5b, 0x61, 0x00, 0xdc, 0x45, 0xe2, 0xa1, 0xf4, 0x1e, 0x7b, - 0x01, 0x7a, 0x84, 0x36, 0xa4, 0xa8, 0x1c, 0x0d, 0x3d, 0xde, 0x57, 0x66, 0x73, 0x4e, 0xaf, 0xee, - 0xb0, 0xb0, 0x69, 0x0c, 0x13, 0xba, 0x76, 0xff, 0x2e, 0xb6, 0x16, 0xf9, 0xfc, 0xd6, 0x09, 0x5b, - 0xc7, 0x37, 0x65, 0x84, 0xd5, 0x82, 0x8a, 0xd7, 0x5b, 0x57, 0xe3, 0x0e, 0x89, 0xbe, 0x05, 0x05, - 0x55, 0x2e, 0x9f, 0x94, 0x8a, 0x53, 0xdc, 0xb7, 0x00, 0xb2, 0x6a, 0x7b, 0x8e, 0xdf, 0x6e, 0xa4, - 0x6d, 0x13, 0xb6, 0xbc, 0xaa, 0x8e, 0x44, 0x11, 0x50, 0x32, 0x91, 0x56, 0xa2, 0x22, 0x3f, 0x2f, - 0x08, 0xbb, 0x4d, 0xbb, 0x69, 0xe6, 0xb1, 0xc2, 0x70, 0x79, 0x15, 0x54, 0xad, 0x4a, 0x29, 0xef, - 0xa9, 0x3e, 0x64, 0x8d, 0xf1, 0x90, 0xf4, 0xa7, 0x93, 0x8c, 0x7a, 0x02, 0x4d, 0x38, 0x1f, 0x58, - 0xb8, 0xe4, 0x7c, 0xe1, 0x66, 0x1c, 0x72, 0x30, 0xf3, 0x4c, 0xf4, 0x24, 0xd1, 0x2d, 0xb7, 0xf1, - 0x5a, 0x0f, 0xb8, 0x20, 0xc5, 0x90, 0xe5, 0xca, 0x45, 0x84, 0x5c, 0x08, 0x08, 0xbf, 0xf9, 0x69, - 0x41, 0xf5, 0x49, 0x85, 0x31, 0x35, 0x14, 0x69, 0x12, 0x57, 0x9c, 0xc8, 0xb7]); - -// X25519 key -let g_x25519PubData = new Uint8Array([ - 0x9c, 0xf6, 0x7a, 0x8d, 0xce, 0xc2, 0x7f, 0xa7, 0xd9, 0xfd, 0xf1, 0xad, 0xac, 0xf0, 0xb3, 0x8c, - 0xe8, 0x16, 0xa2, 0x65, 0xcc, 0x18, 0x55, 0x60, 0xcd, 0x2f, 0xf5, 0xe5, 0x72, 0xc9, 0x3c, 0x54]); -// X25519 public key -let g_x25519PriData = new Uint8Array([ - 0x20, 0xd5, 0xbb, 0x54, 0x6f, 0x1f, 0x00, 0x30, 0x4e, 0x33, 0x38, 0xb9, 0x8e, 0x6a, 0xdf, 0xad, - 0x33, 0x6f, 0x51, 0x23, 0xff, 0x4d, 0x95, 0x26, 0xdc, 0xb0, 0x74, 0xb2, 0x5c, 0x7e, 0x85, 0x6c]); - -// RSA key -let g_nData = new Uint8Array([ - 0xb6, 0xd8, 0x9b, 0x33, 0x78, 0xa2, 0x63, 0x21, 0x84, 0x47, 0xa1, 0x72, 0 x3d, 0x73, 0x10, 0xbd, - 0xe9, 0x5d, 0x78, 0x44, 0x3d, 0x80, 0x18, 0x12, 0x60, 0xed, 0x29, 0x3e, 0xc7, 0x23, 0x0d, 0x3f, - 0x02, 0x59, 0x28, 0xe2, 0x8f, 0x83, 0xdf, 0x37, 0x4b, 0x77, 0xce, 0x5f, 0xb6, 0xcd, 0x61, 0x72, - 0xee, 0x01, 0xe2, 0x37, 0x4d, 0xfd, 0x4f, 0x39, 0xcf, 0xbd, 0xff, 0x84, 0x57, 0x44, 0xa5, 0x03]); -let g_eData = new Uint8Array([0x01, 0x00, 0x01]); -let g_dData = new Uint8Array([ - 0x35, 0x63, 0x89, 0xed, 0xbd, 0x8b, 0xac, 0xe6, 0x5c, 0x79, 0x8d, 0xea, 0x8d, 0x86, 0xcb, 0x9c, - 0xa8, 0x47, 0x62, 0x96, 0x8a, 0x5e, 0x9c, 0xa8, 0xc1, 0x24, 0x7e, 0xa6, 0x95, 0xfe, 0xe6, 0x1e, - 0xc0, 0xf3, 0x29, 0x76, 0xbb, 0x4d, 0xe4, 0xbc, 0x78, 0x64, 0xe1, 0x79, 0xcd, 0x8a, 0x45, 0xac, - 0x5c, 0x88, 0xea, 0xb4, 0x10, 0xd8, 0x90, 0x65, 0x7b, 0x94, 0xe8, 0x87, 0x30, 0x2a, 0x04, 0x01]); -let g_pubData = new Uint8Array([ - 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, - 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0x9e, 0x93, 0x57, 0xc4, 0xab, 0xde, 0x30, - 0xc5, 0x3f, 0x3b, 0x33, 0xa6, 0xdc, 0x4a, 0xdb, 0xbf, 0x12, 0x9e, 0x5d, 0xc4, 0xba, 0x0e, 0x15, - 0x06, 0x41, 0xd8, 0x96, 0x43, 0xca, 0xc5, 0xea, 0x9f, 0xdd, 0xa0, 0x2a, 0xf1, 0x53, 0x46, 0x14, - 0x36, 0x7a, 0xab, 0xbc, 0x92, 0x1b, 0x07, 0xc6, 0x9a, 0x7d, 0x0c, 0xd0, 0xa0, 0x0f, 0x31, 0xd5, - 0x38, 0x84, 0x6c, 0x08, 0xcb, 0x9b, 0x10, 0xa6, 0x4d, 0x02, 0x03, 0x01, 0x00, 0x01]); - -// ECC key -let g_eccXData = new Uint8Array([ - 0xa5, 0xb8, 0xa3, 0x78, 0x1d, 0x6d, 0x76, 0xe0, 0xb3, 0xf5, 0x6f, 0x43, 0x9d, 0xcf, 0x60, 0xf6, - 0x0b, 0x3f, 0x64, 0x45, 0xa8, 0x3f, 0x1a, 0x96, 0xf1, 0xa1, 0xa4, 0x5d, 0x3e, 0x2c, 0x3f, 0x13]); -let g_eccYData = new Uint8Array([ - 0xd7, 0x81, 0xf7, 0x2a, 0xb5, 0x8d, 0x19, 0x3d, 0x9b, 0x96, 0xc7, 0x6a, 0x10, 0xf0, 0xaa, 0xbc, - 0x91, 0x6f, 0x4d, 0xa7, 0x09, 0xb3, 0x57, 0x88, 0x19, 0x6f, 0x00, 0x4b, 0xad, 0xee, 0x34, 0x35]); -let g_eccZData = new Uint8Array([ - 0xfb, 0x8b, 0x9f, 0x12, 0xa0, 0x83, 0x19, 0xbe, 0x6a, 0x6f, 0x63, 0x2a, 0x7c, 0x86, 0xba, 0xca, - 0x64, 0x0b, 0x88, 0x96, 0xe2, 0xfa, 0x77, 0xbc, 0x71, 0xe3, 0x0f, 0x0f, 0x9e, 0x3c, 0xe5, 0xf9]); -let g_eccPubData = new Uint8Array([ - 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, - 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xa5, 0xb8, 0xa3, 0x78, 0x1d, - 0x6d, 0x76, 0xe0, 0xb3, 0xf5, 0x6f, 0x43, 0x9d, 0xcf, 0x60, 0xf6, 0x0b, 0x3f, 0x64, 0x45, 0xa8, - 0x3f, 0x1a, 0x96, 0xf1, 0xa1, 0xa4, 0x5d, 0x3e, 0x2c, 0x3f, 0x13, 0xd7, 0x81, 0xf7, 0x2a, 0xb5, - 0x8d, 0x19, 0x3d, 0x9b, 0x96, 0xc7, 0x6a, 0x10, 0xf0, 0xaa, 0xbc, 0x91, 0x6f, 0x4d, 0xa7, 0x09, - 0xb3, 0x57, 0x88, 0x19, 0x6f, 0x00, 0x4b, 0xad, 0xee, 0x34, 0x35]); - -// Import the DH2048 key. -async function ImportDhTest(alg, keyType) { - let importKeyAlias = 'import_dh_key'; - let 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_2048 - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_IMPORT_KEY_TYPE, - value: huks.HuksImportKeyType.HUKS_KEY_TYPE_PUBLIC_KEY - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) - } - huksOptions.properties[0].value = alg; - huksOptions.properties[3].value = keyType; - - // Compare the key types. - if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR) { - /* Concatenate the huksOptions.inData field with a non-public key in the following format: - * keyAlg type (4 bytes) + key_dh length (4 bytes) + - * g_dhPubData length (4 bytes) + g_dhPriData length (4 bytes) + - * Reserved size (4 bytes) + g_dhPubData + g_dhPriData - */ - // Key pair - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_DH, huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048, g_dhPubData.length, g_dhPriData.length, 0]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - - let strXData = strMaterial.concat(Uint8ArrayToString(g_dhPubData)); - let strData = strXData.concat(Uint8ArrayToString(g_dhPriData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY) { - // Private key - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_DH, huks.HuksKeySize.HUKS_DH_KEY_SIZE_2048, 0, g_dhPriData.length, 0]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - - let strData = strMaterial.concat(Uint8ArrayToString(g_dhPriData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PUBLIC_KEY) { - // Public key - huksOptions.inData = g_dhX509PubData; - } + /* + * Export the public key material of the wrapping key. + */ + await publicExportKeyFunc(wrapAlias, huksOptions); - await publicImportKeyFunc(importKeyAlias, huksOptions); - await publicDeleteKeyFunc(importKeyAlias, huksOptions); -} + /*---------------------------------------------------------------------------------------------- + * The processes of generating an ECC key pair, performing ECDH key agreement, generating a k3, and encrypting k1' and k3 on the service side are omitted. + *----------------------------------------------------------------------------------------------*/ + + /* Encapsulate the key material to be imported. + * Create the importOptions.inData field in the following format: + * pk2 length (4 bytes) + pk2 data + AAD2 length (4 bytes) + AAD2 data + + * Nonce2 length (4 bytes) + Nonce2 data + AEAD2 length (4 bytes) + AEAD2 data + + * k3 ciphertext length (4 bytes) + k3 data + AAD3 length (4 bytes) + AAD3 data + + * Nonce3 length (4 bytes) +Nonce3 data + AEAD3 length (4 bytes) + AEAD3 data + + * k1'_size length (4 bytes) + k1'_size + k1'_enc length (4 bytes) + k1'_enc data + */ + let inputKey = new Uint8Array([ + 0x5b, 0x00, 0x00, 0x00, // ECC-P-256 public key length (DER format defined in X.509): 91 + // ECC-P-256 public key + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xc0, 0xfe, 0x1c, 0x67, 0xde, + 0x86, 0x0e, 0xfb, 0xaf, 0xb5, 0x85, 0x52, 0xb4, 0x0e, 0x1f, 0x6c, 0x6c, 0xaa, 0xc5, 0xd9, 0xd2, + 0x4d, 0xb0, 0x8a, 0x72, 0x24, 0xa1, 0x99, 0xaf, 0xfc, 0x3e, 0x55, 0x5a, 0xac, 0x99, 0x3d, 0xe8, + 0x34, 0x72, 0xb9, 0x47, 0x9c, 0xa6, 0xd8, 0xfb, 0x00, 0xa0, 0x1f, 0x9f, 0x7a, 0x41, 0xe5, 0x44, + 0x3e, 0xb2, 0x76, 0x08, 0xa2, 0xbd, 0xe9, 0x41, 0xd5, 0x2b, 0x9e, + + 0x10, 0x00, 0x00, 0x00, // AAD2 length: 16 + // AAD2 + 0xbf, 0xf9, 0x69, 0x41, 0xf5, 0x49, 0x85, 0x31, 0x35, 0x14, 0x69, 0x12, 0x57, 0x9c, 0xc8, 0xb7, + + 0x10, 0x00, 0x00, 0x00, // Nonce2 length: 16 + // Nonce2 + 0x2d, 0xb7, 0xf1, 0x5a, 0x0f, 0xb8, 0x20, 0xc5, 0x90, 0xe5, 0xca, 0x45, 0x84, 0x5c, 0x08, 0x08, + + 0x10, 0x00, 0x00, 0x00, // AEAD2 length: 16 + // AEAD2 + 0x43, 0x25, 0x1b, 0x2f, 0x5b, 0x86, 0xd8, 0x87, 0x04, 0x4d, 0x38, 0xc2, 0x65, 0xcc, 0x9e, 0xb7, + + 0x20, 0x00, 0x00, 0x00, // k3 ciphertext length: 32 + // k3 ciphertext + 0xf4, 0xe8, 0x93, 0x28, 0x0c, 0xfa, 0x4e, 0x11, 0x6b, 0xe8, 0xbd, 0xa8, 0xe9, 0x3f, 0xa7, 0x8f, + 0x2f, 0xe3, 0xb3, 0xbf, 0xaf, 0xce, 0xe5, 0x06, 0x2d, 0xe6, 0x45, 0x5d, 0x19, 0x26, 0x09, 0xe7, + + 0x10, 0x00, 0x00, 0x00, // AAD3 length: 16 + // AAD3 + 0xf4, 0x1e, 0x7b, 0x01, 0x7a, 0x84, 0x36, 0xa4, 0xa8, 0x1c, 0x0d, 0x3d, 0xde, 0x57, 0x66, 0x73, + + 0x10, 0x00, 0x00, 0x00, // Nonce3 length: 16 + // Nonce3 + 0xe3, 0xff, 0x29, 0x97, 0xad, 0xb3, 0x4a, 0x2c, 0x50, 0x08, 0xb5, 0x68, 0xe1, 0x90, 0x5a, 0xdc, + + 0x10, 0x00, 0x00, 0x00, // AEAD3 length: 16 + // AEAD3 + 0x26, 0xae, 0xdc, 0x4e, 0xa5, 0x6e, 0xb1, 0x38, 0x14, 0x24, 0x47, 0x1c, 0x41, 0x89, 0x63, 0x11, + + 0x04, 0x00, 0x00, 0x00, // Length of k1_size: 4 bytes + // k1_size: 32 bytes + 0x20, 0x00, 0x00, 0x00, + + 0x20, 0x00, 0x00, 0x00, // Ciphertext length of the key to be imported: 32 bytes + // Ciphertext of the key to be imported + 0x0b, 0xcb, 0xa9, 0xa8, 0x5f, 0x5a, 0x9d, 0xbf, 0xa1, 0xfc, 0x72, 0x74, 0x87, 0x79, 0xf2, 0xf4, + 0x22, 0x0c, 0x8a, 0x4d, 0xd8, 0x7e, 0x10, 0xc8, 0x44, 0x17, 0x95, 0xab, 0x3b, 0xd2, 0x8f, 0x0a + ]); + importOptions.inData = inputKey; -// Import the ECC256 key. -async function ImportEccTest(alg, keyType) { - let importKeyAlias = 'import_ecc_key'; - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_ECC - } - 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_ECC_KEY_SIZE_256 - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_IMPORT_KEY_TYPE, - value: huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) - } - huksOptions.properties[0].value = alg; - huksOptions.properties[3].value = keyType; - - // Compare the key types. - if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR) { - /* Concatenate the huksOptions.inData field with a non-public key in the following format: - * keyAlg type (4 bytes) + key_ecc length (4 bytes) + - * g_eccXData length (4 bytes) + g_eccYData length (4 bytes) + - * g_eccZData length (4 bytes) + g_eccXData + - * g_eccYData + g_eccZData - */ - // Key pair - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_ECC, huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256, g_eccXData.length, g_eccYData.length, g_eccZData.length]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - - let strXData = strMaterial.concat(Uint8ArrayToString(g_eccXData)); - let strYData = strXData.concat(Uint8ArrayToString(g_eccYData)); - let strData = strYData.concat(Uint8ArrayToString(g_eccZData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY) { - // Private key - huksOptions.properties[3].value == huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_ECC, huks.HuksKeySize.HUKS_ECC_KEY_SIZE_256, 0, 0, g_eccZData.length]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - - let strData = strMaterial.concat(Uint8ArrayToString(g_eccZData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PUBLIC_KEY) { - // Public key - huksOptions.inData = g_eccPubData; - } + /* + * Import the wrapped key material. + */ + await publicImportWrappedKey(importAlias, wrapAlias, importOptions); - await publicImportKeyFunc(importKeyAlias, huksOptions); - await publicDeleteKeyFunc(importKeyAlias, huksOptions); + /* + * Delete the wrapping key. + */ + await publicDeleteKeyFunc(wrapAlias, huksOptions); } +``` -// Import the RSA512 key. -async function ImportRsaTest(alg, keyType) { - let importKeyAlias = 'import_rsa_key'; - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_RSA - } - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN - } - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_PSS - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_512 - } - properties[5] = { - tag: huks.HuksTag.HUKS_TAG_IMPORT_KEY_TYPE, - value: huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) - } - huksOptions.properties[0].value = alg; - huksOptions.properties[3].value = keyType; - - // Compare the key types. - if (huksOptions.properties[5].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR) { - /* Concatenate the huksOptions.inData field with a non-public key in the following format: - * keyAlg type (4 bytes) + key_rsa length (4 bytes) + - * g_nData length (4 bytes) + g_eData length (4 bytes) + - * g_dData length (4 bytes) + g_nData + - * g_eData + g_dData - */ - // Key pair - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_RSA, huks.HuksKeySize.HUKS_RSA_KEY_SIZE_512, g_nData.length, g_eData.length, g_dData.length]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - let strNData = strMaterial.concat(Uint8ArrayToString(g_nData)); - let strEData = strNData.concat(Uint8ArrayToString(g_eData)); - let strData = strEData.concat(Uint8ArrayToString(g_dData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[5].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY) { - // Private key - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_RSA, huks.HuksKeySize.HUKS_RSA_KEY_SIZE_512, g_nData.length, 0, g_dData.length]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - let strNData = strMaterial.concat(Uint8ArrayToString(g_nData)); - let strData = strNData.concat(Uint8ArrayToString(g_dData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[5].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PUBLIC_KEY) { - // Public key - huksOptions.inData = g_pubData; - } - await publicImportKeyFunc(importKeyAlias, huksOptions); - await publicDeleteKeyFunc(importKeyAlias, huksOptions); -} +**Verification** -// Import the X25519 key. -async function ImportX25519Test(alg, keyType) { - let importKeyAlias = 'import_x25519_key'; - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_X25519 - } - 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_CURVE25519_KEY_SIZE_256 - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_IMPORT_KEY_TYPE, - value: huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) - } - huksOptions.properties[0].value = alg; - huksOptions.properties[3].value = keyType; - - // Compare the key types. - if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR) { - /* Concatenate the huksOptions.inData field with a non-public key in the following format: - * keyAlg type (4 bytes) + key_x25519 length (4 bytes) + - * g_x25519PubData length (4) + g_x25519PriData length (4) + - * Reserved size (4 bytes) + g_x25519PubData + - * g_x25519PriData - */ - // Key pair - let Material = new Uint32Array([huks.HuksKeyAlg.HUKS_ALG_X25519, huks.HuksKeySize.HUKS_CURVE25519_KEY_SIZE_256, g_x25519PriData.length, g_x25519PubData.length, 0]); - let u8Material = Uint32ToUint8(Material); - let strMaterial = Uint8ArrayToString(u8Material); - let strXData = strMaterial.concat(Uint8ArrayToString(g_x25519PubData)); - let strData = strXData.concat(Uint8ArrayToString(g_x25519PriData)); - huksOptions.inData = StringToUint8Array(strData); - } else if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY) { - // Private key - huksOptions.inData = g_x25519PriData; - } else if (huksOptions.properties[3].value === huks.HuksImportKeyType.HUKS_KEY_TYPE_PUBLIC_KEY) { - // Public key - huksOptions.inData = g_x25519PubData; - } - await publicImportKeyFunc(importKeyAlias, huksOptions); - await publicDeleteKeyFunc(importKeyAlias, huksOptions); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testExportRsa') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(() => { - testExportRsa(); - }) +Check whether the key exists. If yes, the key is imported successfully. - Button() { - Text('testImportDh') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(() => { - ImportDhTest(huks.HuksKeyAlg.HUKS_ALG_DH, huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY); - }) +**Sample code** - Button() { - Text('testImportRsa') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(() => { - ImportRsaTest(huks.HuksKeyAlg.HUKS_ALG_RSA, huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR); - }) +```ts +import huks from '@ohos.security.huks'; - Button() { - Text('testImportX25519') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(() => { - ImportX25519Test(huks.HuksKeyAlg.HUKS_ALG_X25519, huks.HuksImportKeyType.HUKS_KEY_TYPE_PRIVATE_KEY); - }) +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let keyAlias = 'importAlias'; +let isKeyExist; - Button() { - Text('testImportEcc') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(() => { - ImportEccTest(huks.HuksKeyAlg.HUKS_ALG_ECC, huks.HuksImportKeyType.HUKS_KEY_TYPE_PUBLIC_KEY); - }) +let keyProperties = new Array(); +keyProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES, +} +let huksOptions = { + properties: keyProperties, // It cannot be empty. + inData: new Uint8Array(new Array()) // It cannot be empty. +} +try { + huks.isKeyItemExist(keyAlias, huksOptions, function (error, data) { + if (error) { + console.error(`callback: isKeyItemExist failed, code: ${error.code}, msg: ${error.message}`); + } else { + if (data !== null && data.valueOf() !== null) { + isKeyExist = data.valueOf(); + console.info(`callback: isKeyItemExist success, isKeyExist = ${isKeyExist}`); + } } - .width('100%') - .height('100%') - } + }); +} catch (error) { + console.error(`callback: isKeyItemExist input arg invalid, code: ${error.code}, msg: ${error.message}`); } ``` -### Secure Key Import -The service invoker and HUKS negotiate a shared symmetric key to encrypt and decrypt the intermediate key and the key to be imported. After the encrypted key is imported, it is decrypted and saved in HUKS. The keys in plaintext can be processed in HUKS only. +## Common Key Operations -The development procedure is as follows: +**When to Use** -1. Generate a key pair in HUKS. The key pair is used to encrypt the key to import. -2. Export the public key of the key pair and obtain a shared secret through key agreement. -3. Generate intermediate key materials to encrypt the key. -4. Import the key. +To 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). -**Supported Key Types** +**General Development Process** -AES128, AES192, AES256, RSA512, RSA768, RSA1024, RSA2048, RSA3072, RSA4096, HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512, ECC224, ECC256, ECC384, ECC521, Curve25519, DSA, SM2, SM3, SM4 +The HUKS operates data based on key sessions. The general process is as follows: +1. (Mandatory) Use [huks.initSession()](../reference/apis/js-apis-huks.md#huksinitsession9) to initialize a key session.
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). +2. (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 cipher algorithm requires operations by data segment. Otherwise, skip this step. +3. (Mandatory) Use [huks.finishSession()](../reference/apis/js-apis-huks.md#huksfinishsession9) to finalize the key session operation.
Pass in the last data segment and perform 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. -> **NOTICE** -> -> - When generating a public key, set **HUKS_TAG_PURPOSE = HUKS_KEY_PURPOSE_UNWRAP**. -> - Set **HUKS_TAG_IMPORT_KEY_TYPE = HUKS_KEY_TYPE_KEY_PAIR**. -> - When importing a key in secure mode, add **HUKS_TAG_UNWRAP_ALGORITHM_SUITE** with value set to **HUKS_UNWRAP_SUITE_X25519_AES_256_GCM_NOPADDING** or **HUKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING**. -> - The key alias cannot exceed 64 bytes. +### Encryption and Decryption +```ts +/* + * Encrypt and decrypt data using an SM4 128-bit key and return the result in a callback. + */ +import huks from '@ohos.security.huks'; + +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let srcKeyAlias = 'sm4_Key'; +let IV = '0000000000000000'; +let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; +let encryptUpdateResult = new Array(); +let handle; +let updateResult = new Array(); +let finishOutData; + +/* Configure the key generation parameter set and key encryption parameter set. */ +let properties = new Array(); +properties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM4, +} +properties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, +} +properties[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, +} +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC, +} +properties[4] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +let huksOptions = { + properties: properties, + inData: new Uint8Array(new Array()) +} -Before you get started, understand the following variables: +let propertiesEncrypt = new Array(); +propertiesEncrypt[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM4, +} +propertiesEncrypt[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, +} +propertiesEncrypt[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, +} +propertiesEncrypt[3] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +propertiesEncrypt[4] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC, +} +propertiesEncrypt[5] = { + tag: huks.HuksTag.HUKS_TAG_IV, + value: StringToUint8Array(IV), +} +let encryptOptions = { + properties: propertiesEncrypt, + inData: new Uint8Array(new Array()) +} -| Parameter | Type | Mandatory| Description | -| -------------- | ----------- | ---- | -------------------------------- | -| importAlias | string | Yes | Alias of the key to import. | -| wrapAlias | string | Yes | Alias of the key. | -| genWrapOptions | HuksOptions | Yes | Tags required for generating the key.| -| importOptions | HuksOptions | Yes | Tags required for importing the encrypted key. | +/* Modify the key encryption parameter set to the decryption parameter set. */ +propertiesEncrypt.splice(1, 1, { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, +}); +let decryptOptions = { + properties: propertiesEncrypt, + inData: new Uint8Array(new Array()) +} -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). +function StringToUint8Array(str) { + let arr = []; + for (let i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + return new Uint8Array(arr); +} -**Example** +function Uint8ArrayToString(fileData) { + let dataString = ''; + for (let i = 0; i < fileData.length; i++) { + dataString += String.fromCharCode(fileData[i]); + } + return dataString; +} -```ts -import huks from '@ohos.security.huks'; +function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { + return new Promise((resolve, reject) => { + try { + huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); +} -async function publicExportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback export`); +async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback generateKeyItem`); + let throwObject = {isThrow: false}; try { - await exportKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); - if (data.outData !== null) { - exportKey = data.outData; - } + await generateKeyItem(keyAlias, huksOptions, throwObject) + .then((data) => { + console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: exportKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { +function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { + huks.initSession(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -831,30 +791,37 @@ function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise< } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -async function publicImportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter promise importKeyItem`); +async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback doInit`); + let throwObject = {isThrow: false}; try { - await importKeyItem(keyAlias, huksOptions) + await initSession(keyAlias, huksOptions, throwObject) .then ((data) => { - console.info(`callback: importKeyItem success, data = ${JSON.stringify(data)}`); + console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); + handle = data.handle; }) - .catch(error => { - console.error(`callback: importKeyItem failed, code: ${error.code}, msg: ${error.message}`); + .catch((error) => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doInit failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: importKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function updateSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.importKeyItem(keyAlias, huksOptions, function (error, data) { + huks.updateSession(handle, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -862,30 +829,36 @@ function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -async function publicImportWrappedKey(keyAlias:string, wrappingKeyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback importWrappedKeyItem`); +async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { + console.info(`enter callback doUpdate`); + let throwObject = {isThrow: false}; try { - await importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions) + await updateSession(handle, huksOptions, throwObject) .then ((data) => { - console.info(`callback: importWrappedKeyItem success, data = ${JSON.stringify(data)}`); + console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: importWrappedKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: importWrappedKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function importWrappedKeyItem(keyAlias:string, wrappingKeyAlias:string, huksOptions:huks.HuksOptions) { +function finishSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.importWrappedKeyItem(keyAlias, wrappingKeyAlias, huksOptions, function (error, data) { + huks.finishSession(handle, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -893,27 +866,34 @@ function importWrappedKeyItem(keyAlias:string, wrappingKeyAlias:string, huksOpti } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); +async function publicFinishFunc(handle:number, huksOptions:huks.HuksOptions) { + console.info(`enter callback doFinish`); + let throwObject = {isThrow: false}; try { - await deleteKeyItem(keyAlias, huksOptions) + await finishSession(handle, huksOptions, throwObject) .then ((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + finishOutData = data.outData; + console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { @@ -924,206 +904,157 @@ function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -let importAlias = "importAlias"; -let wrapAlias = "wrappingKeyAlias"; -let exportKey; +async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback deleteKeyItem`); + let throwObject = {isThrow: false}; + try { + await deleteKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: deletKeeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + } +} -let inputEccPair = new Uint8Array([ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0xa5, 0xb8, 0xa3, 0x78, 0x1d, 0x6d, 0x76, 0xe0, 0xb3, 0xf5, 0x6f, 0x43, - 0x9d, 0xcf, 0x60, 0xf6, 0x0b, 0x3f, 0x64, 0x45, 0xa8, 0x3f, 0x1a, 0x96, 0xf1, 0xa1, 0xa4, 0x5d, - 0x3e, 0x2c, 0x3f, 0x13, 0xd7, 0x81, 0xf7, 0x2a, 0xb5, 0x8d, 0x19, 0x3d, 0x9b, 0x96, 0xc7, 0x6a, - 0x10, 0xf0, 0xaa, 0xbc, 0x91, 0x6f, 0x4d, 0xa7, 0x09, 0xb3, 0x57, 0x88, 0x19, 0x6f, 0x00, 0x4b, - 0xad, 0xee, 0x34, 0x35, 0xfb, 0x8b, 0x9f, 0x12, 0xa0, 0x83, 0x19, 0xbe, 0x6a, 0x6f, 0x63, 0x2a, - 0x7c, 0x86, 0xba, 0xca, 0x64, 0x0b, 0x88, 0x96, 0xe2, 0xfa, 0x77, 0xbc, 0x71, 0xe3, 0x0f, 0x0f, - 0x9e, 0x3c, 0xe5, 0xf9]); +async function testSm4Cipher() { + /* Generate a key. */ + await publicGenKeyFunc(srcKeyAlias, huksOptions); -let 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_256 -}; -properties[2] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_UNWRAP -}; -properties[3] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 -}; -properties[4] = { - tag: huks.HuksTag.HUKS_TAG_IMPORT_KEY_TYPE, - value: huks.HuksImportKeyType.HUKS_KEY_TYPE_KEY_PAIR, -}; -let huksOptions = { - properties: properties, - inData: inputEccPair -}; - -let importProperties = new Array(); -importProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES -}; -importProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256 -}; -importProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT -}; -importProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_CBC -}; -importProperties[4] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE -}; -importProperties[5] = { - tag: huks.HuksTag.HUKS_TAG_UNWRAP_ALGORITHM_SUITE, - value: huks.HuksUnwrapSuite.HUKS_UNWRAP_SUITE_ECDH_AES_256_GCM_NOPADDING -}; -let importOptions = { - properties: importProperties, - inData: new Uint8Array(new Array()) -}; - -async function importWrappedKeyItemTest() { + /* Encrypt the key. */ + await publicInitFunc(srcKeyAlias, encryptOptions); - console.info(`enter ImportWrapKey test`); - await publicImportKeyFunc(wrapAlias, huksOptions); + encryptOptions.inData = StringToUint8Array(cipherInData); + await publicUpdateFunc(handle, encryptOptions); + encryptUpdateResult = updateResult; - await publicExportKeyFunc(wrapAlias, huksOptions); + encryptOptions.inData = new Uint8Array(new Array()); + await publicFinishFunc(handle, encryptOptions); + if (finishOutData === cipherInData) { + console.info('test finish encrypt err '); + } else { + console.info('test finish encrypt success'); + } - /* The following operation does not involve calling of HUKS APIs, and the specific implementation is not provided here. - * For example, import keyA. - * 1. Use ECC to generate a public and private key pair named keyB. The public key is keyB_pub, and the private key is keyB_pri. - * 2. Use keyB_pri and the public key obtained from wrappingAlias to negotiate the shared key share_key. - * 3. Randomly generate a key kek to encrypt keyA using AES-GCM. During the encryption, record nonce1, aad1, ciphertext keyA_enc, and encrypted tag1. - * 4. Use share_key to encrypt kek using AES-GCM. During the encryption, record nonce2, aad2, ciphertext kek_enc, and encrypted tag2. - * 5. Generate the **importOptions.inData** field in the following format: - * keyB_pub length (4 bytes) + keyB_pub + aad2 length (4 bytes) + aad2 + - * nonce2 length (4 bytes) + nonce2 + tag2 length (4 bytes) + tag2 + - * kek_enc length (4 bytes) + kek_enc + aad1 length (4 bytes) + aad1 + - * nonce1 length (4 bytes) + nonce1 + tag1 length (4 bytes) + tag1 + - * Memory occupied by the keyA length (4 bytes) + keyA length + keyA_enc length (4 bytes) + keyA_enc - */ - let inputKey = new Uint8Array([ - 0x5b, 0x00, 0x00, 0x00, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, - 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xc0, - 0xfe, 0x1c, 0x67, 0xde, 0x86, 0x0e, 0xfb, 0xaf, 0xb5, 0x85, 0x52, 0xb4, 0x0e, 0x1f, 0x6c, 0x6c, - 0xaa, 0xc5, 0xd9, 0xd2, 0x4d, 0xb0, 0x8a, 0x72, 0x24, 0xa1, 0x99, 0xaf, 0xfc, 0x3e, 0x55, 0x5a, - 0xac, 0x99, 0x3d, 0xe8, 0x34, 0x72, 0xb9, 0x47, 0x9c, 0xa6, 0xd8, 0xfb, 0x00, 0xa0, 0x1f, 0x9f, - 0x7a, 0x41, 0xe5, 0x44, 0x3e, 0xb2, 0x76, 0x08, 0xa2, 0xbd, 0xe9, 0x41, 0xd5, 0x2b, 0x9e, 0x10, - 0x00, 0x00, 0x00, 0xbf, 0xf9, 0x69, 0x41, 0xf5, 0x49, 0x85, 0x31, 0x35, 0x14, 0x69, 0x12, 0x57, - 0x9c, 0xc8, 0xb7, 0x10, 0x00, 0x00, 0x00, 0x2d, 0xb7, 0xf1, 0x5a, 0x0f, 0xb8, 0x20, 0xc5, 0x90, - 0xe5, 0xca, 0x45, 0x84, 0x5c, 0x08, 0x08, 0x10, 0x00, 0x00, 0x00, 0x43, 0x25, 0x1b, 0x2f, 0x5b, - 0x86, 0xd8, 0x87, 0x04, 0x4d, 0x38, 0xc2, 0x65, 0xcc, 0x9e, 0xb7, 0x20, 0x00, 0x00, 0x00, 0xf4, - 0xe8, 0x93, 0x28, 0x0c, 0xfa, 0x4e, 0x11, 0x6b, 0xe8, 0xbd, 0xa8, 0xe9, 0x3f, 0xa7, 0x8f, 0x2f, - 0xe3, 0xb3, 0xbf, 0xaf, 0xce, 0xe5, 0x06, 0x2d, 0xe6, 0x45, 0x5d, 0x19, 0x26, 0x09, 0xe7, 0x10, - 0x00, 0x00, 0x00, 0xf4, 0x1e, 0x7b, 0x01, 0x7a, 0x84, 0x36, 0xa4, 0xa8, 0x1c, 0x0d, 0x3d, 0xde, - 0x57, 0x66, 0x73, 0x10, 0x00, 0x00, 0x00, 0xe3, 0xff, 0x29, 0x97, 0xad, 0xb3, 0x4a, 0x2c, 0x50, - 0x08, 0xb5, 0x68, 0xe1, 0x90, 0x5a, 0xdc, 0x10, 0x00, 0x00, 0x00, 0x26, 0xae, 0xdc, 0x4e, 0xa5, - 0x6e, 0xb1, 0x38, 0x14, 0x24, 0x47, 0x1c, 0x41, 0x89, 0x63, 0x11, 0x04, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x0b, 0xcb, 0xa9, 0xa8, 0x5f, 0x5a, 0x9d, 0xbf, 0xa1, - 0xfc, 0x72, 0x74, 0x87, 0x79, 0xf2, 0xf4, 0x22, 0x0c, 0x8a, 0x4d, 0xd8, 0x7e, 0x10, 0xc8, 0x44, - 0x17, 0x95, 0xab, 0x3b, 0xd2, 0x8f, 0x0a - ]); + /* Decrypt the key. */ + await publicInitFunc(srcKeyAlias, decryptOptions); - importOptions.inData = inputKey; - await publicImportWrappedKey(importAlias, wrapAlias, importOptions); + decryptOptions.inData = new Uint8Array(encryptUpdateResult); + await publicUpdateFunc(handle, decryptOptions); - await publicDeleteKeyFunc(wrapAlias, huksOptions); - await publicDeleteKeyFunc(importAlias, importOptions); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('importWrappedKeyItemTest') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - importWrappedKeyItemTest(); - }) - } - .width('100%') - .height('100%') + decryptOptions.inData = new Uint8Array(new Array()); + await publicFinishFunc(handle, decryptOptions); + if (finishOutData === cipherInData) { + console.info('test finish decrypt success '); + } else { + console.info('test finish decrypt err'); } + + await publicDeleteKeyFunc(srcKeyAlias, huksOptions); } ``` -### Key Encryption and Decryption - -Use the symmetric or asymmetric key stored in HUKS to encrypt or decrypt data based on the specified alias. The keys in plaintext must be in a secure environment during the encryption and decryption process. - -The development procedure is as follows: - -1. Generate a key. -2. Encrypt the key. -3. Decrypt the key. - -**Supported key types**: - -| HUKS_ALG_ALGORITHM | HUKS_TAG_PURPOSE | HUKS_TAG_DIGEST | HUKS_TAG_PADDING | HUKS_TAG_BLOCK_MODE | HUKS_TAG_IV | -| ------------------------------------------------------------ | -------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------- | ----------- | -| HUKS_ALG_SM4 (supported key length: HUKS_SM4_KEY_SIZE_128)| HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT| Optional | HUKS_PADDING_NONE | HUKS_MODE_CTR HUKS_MODE_ECB HUKS_MODE_CBC | Mandatory | -| HUKS_ALG_SM4 (supported key length: HUKS_SM4_KEY_SIZE_128)| HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT| Optional | HUKS_PADDING_PKCS7 | HUKS_MODE_ECB HUKS_MODE_CBC | Mandatory | -| HUKS_ALG_RSA (supported lengths: HUKS_RSA_KEY_SIZE_512, HUKS_RSA_KEY_SIZE_768, HUKS_RSA_KEY_SIZE_1024, HUKS_RSA_KEY_SIZE_2048, HUKS_RSA_KEY_SIZE_3072, HUKS_RSA_KEY_SIZE_4096)| HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT| HUKS_DIGEST_SHA1 HUKS_DIGEST_SHA224 HUKS_DIGEST_SHA256 HUKS_DIGEST_SHA384 HUKS_DIGEST_SHA512 | HUKS_PADDING_NONE HUKS_PADDING_PKCS1_V1_5 HUKS_PADDING_OAEP | HUKS_MODE_ECB | Optional | - -| HUKS_ALG_ALGORITHM | HUKS_TAG_PURPOSE | HUKS_TAG_PADDING | HUKS_TAG_BLOCK_MODE | HUKS_TAG_IV | HUKS_TAG_NONCE | HUKS_TAG_ASSOCIATED_DATA | HUKS_TAG_AE_TAG | -| ------------------------------------------------------------ | ------------------------ | ------------------------------------- | ---------------------------- | ----------- | -------------- | ------------------------ | --------------- | -| HUKS_ALG_AES (supported key lengths: HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256)| HUKS_KEY_PURPOSE_ENCRYPT | HUKS_PADDING_NONE, HUKS_PADDING_PKCS7| HUKS_MODE_CBC | Mandatory | Optional | Optional | Optional | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_ENCRYPT | HUKS_PADDING_NONE | HUKS_MODE_CCM HUKS_MODE_GCM | Optional | Mandatory | Mandatory | Optional | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_ENCRYPT | HUKS_PADDING_NONE | HUKS_MODE_CTR | Mandatory | Optional | Optional | Optional | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_ENCRYPT | HUKS_PADDING_PKCS7 HUKS_PADDING_NONE | HUKS_MODE_ECB | Mandatory | Optional | Optional | Optional | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_DECRYPT | HUKS_PADDING_NONE, HUKS_PADDING_PKCS7| HUKS_MODE_CBC | Mandatory | Optional | Optional | Mandatory | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_DECRYPT | HUKS_PADDING_NONE | HUKS_MODE_CCM HUKS_MODE_GCM | Optional | Mandatory | Mandatory | Optional | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_DECRYPT | HUKS_PADDING_NONE | HUKS_MODE_CTR | Mandatory | Optional | Optional | Optional | -| HUKS_ALG_AES | HUKS_KEY_PURPOSE_DECRYPT | HUKS_PADDING_NONE, HUKS_PADDING_PKCS7| HUKS_MODE_ECB | Mandatory | Optional | Optional | Optional | - -> **NOTE**
-> -> The key alias cannot exceed 64 bytes. - -Before you get started, understand the following variables: +### Signing and Signature Verification +```ts +/* + * Generate and verify a signature using an SM2 key and return the result in a callback. + */ +import huks from '@ohos.security.huks'; -| Parameter | Type | Mandatory| Description | -| -------------- | ----------- | ---- | ------------------------ | -| srcKeyAlias | string | Yes | Alias of the key. | -| huksOptions | HuksOptions | Yes | Tags required for generating the key.| -| encryptOptions | HuksOptions | Yes | Tags required for encrypting the key.| -| decryptOptions | HuksOptions | Yes | Tags required for decrypting the key.| +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let generateKeyAlias = 'sm2_Key'; +let importKeyAlias = 'importKeyAlias'; +let signVerifyInData = 'signVerifyInDataForTest'; +let handle; +let exportKey; +let finishOutData; -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). +/* Configure the parameter set used for generating the key. */ +let generateKeyProperties = new Array(); +generateKeyProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM2, +} +generateKeyProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN | + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY, +} +generateKeyProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, +} +generateKeyProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, +} +let genrateKeyOptions = { + properties: generateKeyProperties, + inData: new Uint8Array(new Array()) +} -**Example 1:** +/* Configure the parameter set used for signing. */ +let signProperties = new Array(); +signProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM2, +} +signProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN +} +signProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, +} +signProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, +} +let signOptions = { + properties: signProperties, + inData: new Uint8Array(new Array()) +} -```ts -/* The cipher operation supports RSA, AES, and SM4 keys. - * - * The following uses the Promise() operation of an SM4 128-bit key as an example. - */ -import huks from '@ohos.security.huks'; +/* Configure the parameter set used for signature verification. */ +let verifyProperties = new Array(); +verifyProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM2, +} +verifyProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY +} +verifyProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, +} +verifyProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, +} +let verifyOptions = { + properties: verifyProperties, + inData: new Uint8Array(new Array()) +} function StringToUint8Array(str) { let arr = []; @@ -1133,33 +1064,47 @@ function StringToUint8Array(str) { return new Uint8Array(arr); } -function Uint8ArrayToString(fileData) { - let dataString = ''; - for (let i = 0; i < fileData.length; i++) { - dataString += String.fromCharCode(fileData[i]); - } - return dataString; +function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { + return new Promise((resolve, reject) => { + try { + huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); } async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { console.info(`enter callback generateKeyItem`); + let throwObject = {isThrow: false}; try { - await generateKeyItem(keyAlias, huksOptions) + await generateKeyItem(keyAlias, huksOptions, throwObject) .then((data) => { console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + huks.initSession(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1167,47 +1112,74 @@ function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter promise doInit`); + console.info(`enter callback doInit`); + let throwObject = {isThrow: false}; try { - await huks.initSession(keyAlias, huksOptions) + await initSession(keyAlias, huksOptions, throwObject) .then ((data) => { - console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); + console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); handle = data.handle; }) - .catch(error => { - console.error(`promise: doInit key failed, code: ${error.code}, msg: ${error.message}`); + .catch((error) => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doInit failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`promise: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); } } +function updateSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { + return new Promise((resolve, reject) => { + try { + huks.updateSession(handle, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); +} + async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { console.info(`enter callback doUpdate`); + let throwObject = {isThrow: false}; try { - await updateSession(handle, huksOptions) + await updateSession(handle, huksOptions, throwObject) .then ((data) => { console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); - updateResult = Array.from(data.outData); }) .catch(error => { - console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { +function finishSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.updateSession(handle, huksOptions, function (error, data) { + huks.finishSession(handle, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1215,6 +1187,7 @@ function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - finishOutData = Uint8ArrayToString(new Uint8Array(updateResult)); + finishOutData = data.outData; console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { +function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.finishSession(handle, huksOptions, function (error, data) { + huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1247,30 +1225,37 @@ function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); + exportKey = data.outData; }) .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: exportKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { + huks.importKeyItem(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1278,157 +1263,214 @@ function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -let IV = '0000000000000000'; -let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; -let srcKeyAlias = 'huksCipherSm4SrcKeyAlias'; -let encryptUpdateResult = new Array(); -let handle; -let updateResult = new Array(); -let finishOutData; - -async function testSm4Cipher() { - /* Integrate the key generation parameter set and key encryption parameter set. */ - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_SM4, - } - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, - } - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_CBC, - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) +async function publicImportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter promise importKeyItem`); + let throwObject = {isThrow: false}; + try { + await importKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: importKeyItem success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: importKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: importKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } +} - let propertiesEncrypt = new Array(); - propertiesEncrypt[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_SM4, - } - propertiesEncrypt[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, - } - propertiesEncrypt[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, - } - propertiesEncrypt[3] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - propertiesEncrypt[4] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_CBC, - } - propertiesEncrypt[5] = { - tag: huks.HuksTag.HUKS_TAG_IV, - value: StringToUint8Array(IV), - } - let encryptOptions = { - properties: propertiesEncrypt, - inData: new Uint8Array(new Array()) +function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { + return new Promise((resolve, reject) => { + try { + huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); +} + +async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback deleteKeyItem`); + let throwObject = {isThrow: false}; + try { + await deleteKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: deletKeeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } +} +async function testSm2SignVerify() { /* Generate a key. */ - await publicGenKeyFunc(srcKeyAlias, huksOptions); + await publicGenKeyFunc(generateKeyAlias, genrateKeyOptions); - /* Encrypt the key. */ - await publicInitFunc(srcKeyAlias, encryptOptions); - - encryptOptions.inData = StringToUint8Array(cipherInData); - await publicUpdateFunc(handle, encryptOptions); - encryptUpdateResult = updateResult; + /* Generate a signature. */ + let signHandle; + let signFinishOutData; + await publicInitFunc(generateKeyAlias, signOptions); - encryptOptions.inData = new Uint8Array(new Array()); - await publicFinishFunc(handle, encryptOptions); - if (finishOutData === cipherInData) { - console.info('test finish encrypt err '); - } else { - console.info('test finish encrypt success'); - } + signHandle = handle; + signOptions.inData = StringToUint8Array(signVerifyInData) + await publicUpdateFunc(signHandle, signOptions); - /* Modify the key encryption parameter set to the decryption parameter set. */ - propertiesEncrypt.splice(1, 1, { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, - }); - let decryptOptions = { - properties: propertiesEncrypt, - inData: new Uint8Array(new Array()) - } + signOptions.inData = new Uint8Array(new Array()); + await publicFinishFunc(signHandle, signOptions); + signFinishOutData = finishOutData; - /* Decrypt the key. */ - await publicInitFunc(srcKeyAlias, decryptOptions); + /* Export the key. */ + await publicExportKeyFunc(generateKeyAlias, genrateKeyOptions); - decryptOptions.inData = new Uint8Array(encryptUpdateResult); - await publicUpdateFunc(handle, decryptOptions); + /* Import the key. */ + verifyOptions.inData = exportKey; + await publicImportKeyFunc(importKeyAlias, verifyOptions); - decryptOptions.inData = new Uint8Array(new Array()); - await publicFinishFunc(handle, decryptOptions); - if (finishOutData === cipherInData) { - console.info('test finish decrypt success '); - } else { - console.info('test finish decrypt err'); - } + /* Verify the signature. */ + let verifyHandle; + await publicInitFunc(importKeyAlias, verifyOptions); - await publicDeleteKeyFunc(srcKeyAlias, huksOptions); -} + verifyHandle = handle; -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testSm4Cipher') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testSm4Cipher(); - }) - } - .width('100%') - .height('100%') - } + verifyOptions.inData = StringToUint8Array(signVerifyInData) + await publicUpdateFunc(verifyHandle, verifyOptions); + + verifyOptions.inData = signFinishOutData; + await publicFinishFunc(verifyHandle, verifyOptions); + + await publicDeleteKeyFunc(generateKeyAlias, genrateKeyOptions); + await publicDeleteKeyFunc(importKeyAlias, genrateKeyOptions); } ``` -**Example 2:** - +### Key Agreement ```ts -/* The cipher operation supports RSA, AES, and SM4 keys. - * - * The following uses the Promise() operation of an AES128 GCM key as an example. +/* + * Perform key agreement using an X25519 256-bit TEMP key and return the result in a callback. */ import huks from '@ohos.security.huks'; +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias"; +let srcKeyAliasSecond = "AgreeX25519KeySecondAlias"; +let agreeX25519InData = 'AgreeX25519TestIndata'; +let finishOutData; +let handle; +let exportKey; +let exportKeyFrist; +let exportKeySecond; + +/* Configure the parameter set used for generating the key. */ +let properties = new Array(); +properties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_X25519, +} +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_CURVE25519_KEY_SIZE_256, +} +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, +} +properties[4] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +properties[5] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC, +} +let HuksOptions = { + properties: properties, + inData: new Uint8Array(new Array()) +} + +/* Configure parameters for the first key agreement. */ +let finishProperties = new Array(); +finishProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, + value: huks.HuksKeyStorageType.HUKS_STORAGE_TEMP, +} +finishProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, + value: true +} +finishProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES, +} +finishProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, +} +finishProperties[4] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, +} +finishProperties[5] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, +} +finishProperties[6] = { + tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, + value: StringToUint8Array(srcKeyAliasFirst+ 'final'), +} +finishProperties[7] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +finishProperties[8] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_ECB, +} +let finishOptionsFrist = { + properties: finishProperties, + inData: StringToUint8Array(agreeX25519InData) +} +/* Configure parameters for the second key agreement. */ +let finishOptionsSecond = { + properties: finishProperties, + inData: StringToUint8Array(agreeX25519InData) +} +finishOptionsSecond.properties.splice(6, 1, { + tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, + value: StringToUint8Array(srcKeyAliasSecond + 'final'), +}) + function StringToUint8Array(str) { let arr = []; for (let i = 0, j = str.length; i < j; ++i) { @@ -1437,33 +1479,47 @@ function StringToUint8Array(str) { return new Uint8Array(arr); } -function Uint8ArrayToString(fileData) { - let dataString = ''; - for (let i = 0; i < fileData.length; i++) { - dataString += String.fromCharCode(fileData[i]); - } - return dataString; +function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { + return new Promise((resolve, reject) => { + try { + huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); } async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { console.info(`enter callback generateKeyItem`); + let throwObject = {isThrow: false}; try { - await generateKeyItem(keyAlias, huksOptions) + await generateKeyItem(keyAlias, huksOptions, throwObject) .then((data) => { console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + huks.initSession(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1471,47 +1527,74 @@ function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter promise doInit`); + console.info(`enter callback doInit`); + let throwObject = {isThrow: false}; try { - await huks.initSession(keyAlias, huksOptions) + await initSession(keyAlias, huksOptions, throwObject) .then ((data) => { - console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); + console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); handle = data.handle; }) - .catch(error => { - console.error(`promise: doInit key failed, code: ${error.code}, msg: ${error.message}`); + .catch((error) => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doInit failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`promise: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); } } +function updateSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { + return new Promise((resolve, reject) => { + try { + huks.updateSession(handle, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); +} + async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { console.info(`enter callback doUpdate`); + let throwObject = {isThrow: false}; try { - await updateSession(handle, huksOptions) + await updateSession(handle, huksOptions, throwObject) .then ((data) => { console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); - updateResult = Array.from(data.outData); }) .catch(error => { - console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { +function finishSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.updateSession(handle, huksOptions, function (error, data) { + huks.finishSession(handle, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1519,6 +1602,7 @@ function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - updateResult = updateResult.concat(Array.from(data.outData)); + finishOutData = data.outData; console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { +function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { - huks.finishSession(handle, huksOptions, function (error, data) { + huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1551,27 +1640,34 @@ function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); + exportKey = data.outData; }) .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: exportKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { @@ -1582,227 +1678,165 @@ function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -let AAD = '0000000000000000'; -let NONCE = '000000000000'; -let AEAD = '0000000000000000'; -let cipherInData = 'Hks_AES_Cipher_Test_00000000000000000000000000000000000000000000000000000_string'; -let srcKeyAlias = 'huksCipherSm4SrcKeyAlias'; -let updateResult = new Array(); -let encryptUpdateResult = new Array(); -let decryptUpdateResult = new Array(); -let handle; -let finishOutData; - -async function testAesCipher() { - /* Integrate the key generation parameter set and key encryption parameter set. */ - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES, - } - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, - } - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128, - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_GCM, - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) +async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback deleteKeyItem`); + let throwObject = {isThrow: false}; + try { + await deleteKeyItem(keyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: deletKeeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } +} - let propertiesEncrypt = new Array(); - propertiesEncrypt[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES, - } - propertiesEncrypt[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, - } - propertiesEncrypt[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128, - } - propertiesEncrypt[3] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - propertiesEncrypt[4] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_GCM, - } - propertiesEncrypt[5] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, - } - propertiesEncrypt[6] = { - tag: huks.HuksTag.HUKS_TAG_ASSOCIATED_DATA, - value: StringToUint8Array(AAD), - } - propertiesEncrypt[7] = { - tag: huks.HuksTag.HUKS_TAG_NONCE, - value: StringToUint8Array(NONCE), - } - propertiesEncrypt[8] = { - tag: huks.HuksTag.HUKS_TAG_AE_TAG, - value: StringToUint8Array(AEAD), - } - let encryptOptions = { - properties: propertiesEncrypt, - inData: new Uint8Array(new Array()) - } - - /* Generate a key. */ - await publicGenKeyFunc(srcKeyAlias, huksOptions); - - /* Encrypt the key. */ - await publicInitFunc(srcKeyAlias, encryptOptions); - - encryptOptions.inData = StringToUint8Array(cipherInData.slice(0,64)); - await publicUpdateFunc(handle, encryptOptions); - encryptUpdateResult = updateResult; - - encryptOptions.inData = StringToUint8Array(cipherInData.slice(64,80)); - await publicFinishFunc(handle, encryptOptions); - encryptUpdateResult = updateResult; - finishOutData = Uint8ArrayToString(new Uint8Array(encryptUpdateResult)); - if (finishOutData === cipherInData) { - console.info('test finish encrypt err '); - } else { - console.info('test finish encrypt success'); - } - - /* Modify the key encryption parameter set to the decryption parameter set. */ - propertiesEncrypt.splice(1, 1, { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, - }); - propertiesEncrypt.splice(8, 1, { - tag: huks.HuksTag.HUKS_TAG_AE_TAG, - value: new Uint8Array(encryptUpdateResult.splice(encryptUpdateResult.length - 16,encryptUpdateResult.length)) - }); - let decryptOptions = { - properties: propertiesEncrypt, - inData: new Uint8Array(new Array()) - } - - /* Decrypt the key. */ - await publicInitFunc(srcKeyAlias, decryptOptions); +async function testAgree() { + /* 1. Generate two keys and export them. */ + await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions); + await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions); - decryptOptions.inData = new Uint8Array(encryptUpdateResult.slice(0,64)); - await publicUpdateFunc(handle, decryptOptions); - decryptUpdateResult = updateResult; + await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions); + exportKeyFrist = exportKey; + await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions); + exportKeySecond = exportKey; - decryptOptions.inData = new Uint8Array(encryptUpdateResult.slice(64,encryptUpdateResult.length)); - await publicFinishFunc(handle, decryptOptions); - decryptUpdateResult = updateResult; - finishOutData = Uint8ArrayToString(new Uint8Array(decryptUpdateResult)); - if (finishOutData === cipherInData) { - console.info('test finish decrypt success '); - } else { - console.info('test finish decrypt err'); - } + /* Perform key agreement for the first. */ + await publicInitFunc(srcKeyAliasFirst, HuksOptions); + HuksOptions.inData = exportKeySecond; + await publicUpdateFunc(handle, HuksOptions); + await publicFinishFunc(handle, finishOptionsFrist); - await publicDeleteKeyFunc(srcKeyAlias, huksOptions); -} + /* Perform key agreement for the second key. */ + await publicInitFunc(srcKeyAliasSecond, HuksOptions); + HuksOptions.inData = exportKeyFrist; + await publicUpdateFunc(handle, HuksOptions); + await publicFinishFunc(handle, finishOptionsSecond); -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testAesCipher') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testAesCipher(); - }) - } - .width('100%') - .height('100%') - } + await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions); + await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions); } ``` -### Signing and Signature Verification - -The data to be sent can be signed with a unique signature for security purposes. Then, the receiver needs to verify the signature when receiving the data. - -The development procedure is as follows: - -1. Generate a key. -2. Use the key to sign the data to be sent. -3. Export the signature key. -4. Import the signature key. -5. Verify the signature. - -**Supported key types**: - -Only **HksInit()** has requirements on parameters in **paramSet**. The other Init-Update-Finish APIs have no requirements on **paramSet**. - -| HUKS_ALG_ALGORITHM | HUKS_ALG_KEY_SIZE | HUKS_ALG_PURPOSE | HUKS_ALG_PADDING | HUKS_TAG_DIGEST | -| ------------------ | ------------------------------------------------------------ | ---------------------------------------------- | ----------------------- | ------------------------------------------------------------ | -| HUKS_ALG_RSA | HUKS_RSA_KEY_SIZE_512, HUKS_RSA_KEY_SIZE_768, HUKS_RSA_KEY_SIZE_1024, HUKS_RSA_KEY_SIZE_2048, HUKS_RSA_KEY_SIZE_3072, HUKS_RSA_KEY_SIZE_4096| HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | HUKS_PADDING_PKCS1_V1_5 | HUKS_DIGEST_MD5, HUKS_DIGEST_NONE, HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| -| HUKS_ALG_RSA | HUKS_RSA_KEY_SIZE_512, HUKS_RSA_KEY_SIZE_768, HUKS_RSA_KEY_SIZE_1024, HUKS_RSA_KEY_SIZE_2048, HUKS_RSA_KEY_SIZE_3072, HUKS_RSA_KEY_SIZE_4096| HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | HUKS_PADDING_PSS | HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| -| HUKS_ALG_DSA | HUKS_RSA_KEY_SIZE_1024 | HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | Optional | HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| -| HUKS_ALG_ECC | HUKS_ECC_KEY_SIZE_224, HUKS_ECC_KEY_SIZE_256, HUKS_ECC_KEY_SIZE_384, HUKS_ECC_KEY_SIZE_521| HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | Optional | HUKS_DIGEST_NONE, HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| - -The signing and signature verification using Ed25519 involves a hash operation in the algorithm engine. Therefore, the Init-Update-Finish processing is special. - -In the **update()** process, **inData** is sent to HUKS Core and recorded in a .ctx file, without performing hash operation. The signing and signature verification calculations are performed on the combined **inData** in the **finish()** operation. - -| HUKS_ALG_ALGORITHM | HUKS_ALG_KEY_SIZE | HUKS_ALG_PURPOSE | -| ------------------ | ---------------------------- | ----------------------------------------------- | -| HUKS_ALG_ED25519 | HUKS_CURVE25519_KEY_SIZE_256 | HUKS_KEY_PURPOSE_SIGN HUKS_KEY_PURPOSE_VERIFY | - -> **NOTE**
-> -> The key alias cannot exceed 64 bytes. - -Before you get started, understand the following variables: +### Key Derivation +```ts +/* + * The following uses the Promise() operation of an HKDF256 key as an example. + */ +import huks from '@ohos.security.huks'; -| Parameter | Type | Mandatory| Description | -| ----------------- | ----------- | ---- | ------------------------ | -| generateKeyAlias | string | Yes | Alias of the key to generate. | -| importKeyAlias | string | Yes | Alias of the key imported. | -| genrateKeyOptions | HuksOptions | Yes | Tags required for generating the key.| -| signOptions | HuksOptions | Yes | Tags required for signing.| -| verifyOptions | HuksOptions | Yes | Tags required for verifying the signature.| +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let srcKeyAlias = "hkdf_Key"; +let deriveHkdfInData = "deriveHkdfTestIndata"; +let handle; +let finishOutData; +let HuksKeyDeriveKeySize = 32; -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). +/* Configure the parameter set used for generating the key. */ +let properties = new Array(); +properties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES, +} +properties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE, +} +properties[2] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256, +} +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128, +} +let huksOptions = { + properties: properties, + inData: new Uint8Array(new Array()) +} -**Example** +/* Configure the parameter set used for init(). */ +let initProperties = new Array(); +initProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_HKDF, +} +initProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE, +} +initProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256, +} +initProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_DERIVE_KEY_SIZE, + value: HuksKeyDeriveKeySize, +} +let initOptions = { + properties: initProperties, + inData: new Uint8Array(new Array()) +} -```ts -/*The Sign() and Verify() operations support RSA, ECC, SM2, ED25519, and DSA keys. - * - * The following uses an SM2 key in callback-based APIs as an example. - */ -import huks from '@ohos.security.huks'; +/* Configure the parameter set used for finish(). */ +let finishProperties = new Array(); +finishProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, + value: huks.HuksKeyStorageType.HUKS_STORAGE_PERSISTENT, +} +finishProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, + value: true, +} +finishProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_AES, +} +finishProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, +} +finishProperties[4] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | + huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, +} +finishProperties[5] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, +} +finishProperties[6] = { + tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, + value: StringToUint8Array(srcKeyAlias), +} +finishProperties[7] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +finishProperties[8] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_ECB, +} +let finishOptions = { + properties: finishProperties, + inData: new Uint8Array(new Array()) +} function StringToUint8Array(str) { let arr = []; @@ -1812,22 +1846,7 @@ function StringToUint8Array(str) { return new Uint8Array(arr); } -async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); - try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { @@ -1838,28 +1857,33 @@ function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback doInit`); +async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback generateKeyItem`); + let throwObject = {isThrow: false}; try { - await initSession(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback1: doInit success, data = ${JSON.stringify(data)}`); - handle = data.handle; + await generateKeyItem(keyAlias, huksOptions, throwObject) + .then((data) => { + console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); }) - .catch((error) => { - console.error(`callback1: doInit failed, code: ${error.code}, msg: ${error.message}`); + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function initSession(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { +function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { huks.initSession(keyAlias, huksOptions, function (error, data) { @@ -1870,27 +1894,34 @@ function initSession(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { - console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); + console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); + handle = data.handle; }) - .catch(error => { - console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + .catch((error) => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doInit failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { +function updateSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { huks.updateSession(handle, huksOptions, function (error, data) { @@ -1901,28 +1932,33 @@ function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - finishOutData = data.outData;; - console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); + console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { +function finishSession(handle:number, huksOptions:huks.HuksOptions, throwObject) : Promise { return new Promise((resolve, reject) => { try { huks.finishSession(handle, huksOptions, function (error, data) { @@ -1933,62 +1969,37 @@ function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); - exportKey = data.outData; + finishOutData = data.outData; + console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: exportKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); + if (throwObject.isThrow) { + throw(error); } else { - resolve(data); + console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); } }); - } catch (error) { - throw(error); - } - }); -} - -async function publicImportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter promise importKeyItem`); - try { - await importKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: importKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: importKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); } catch (error) { - console.error(`callback: importKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { - huks.importKeyItem(keyAlias, huksOptions, function (error, data) { + huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { if (error) { reject(error); } else { @@ -1996,6 +2007,7 @@ function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); @@ -2003,1471 +2015,577 @@ function importKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { console.info(`enter callback deleteKeyItem`); + let throwObject = {isThrow: false}; try { - await deleteKeyItem(keyAlias, huksOptions) + await deleteKeyItem(keyAlias, huksOptions, throwObject) .then ((data) => { console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: deletKeeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} +async function testDerive() { + /* Generate a key. */ + await publicGenKeyFunc(srcKeyAlias, huksOptions); -let signVerifyInData = 'signVerifyInDataForTest'; -let generateKeyAlias = 'generateKeyAliasForTest'; -let importKeyAlias = 'importKeyAliasForTest'; -let handle; -let exportKey; -let finishOutData; + /* Derive a key. */ + await publicInitFunc(srcKeyAlias, initOptions); -/* Configure the parameters for generating the key. */ -let generateKeyProperties = new Array(); -generateKeyProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_SM2, -} -generateKeyProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY, -} -generateKeyProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, + initOptions.inData = StringToUint8Array(deriveHkdfInData); + await publicUpdateFunc(handle, initOptions); + await publicFinishFunc(handle, finishOptions); + + await publicDeleteKeyFunc(srcKeyAlias, huksOptions); } -generateKeyProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, -} -let genrateKeyOptions = { - properties: generateKeyProperties, - inData: new Uint8Array(new Array()) -} - -/* Configure the parameters for signing. */ -let signProperties = new Array(); -signProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_SM2, -} -signProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_SIGN -} -signProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, -} -signProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, -} -let signOptions = { - properties: signProperties, - inData: new Uint8Array(new Array()) -} - -/* Configure the parameters for signature verification. */ -let verifyProperties = new Array(); -verifyProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_SM2, -} -verifyProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY -} -verifyProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, -} -verifyProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_SM2_KEY_SIZE_256, -} -let verifyOptions = { - properties: verifyProperties, - inData: new Uint8Array(new Array()) -} - -async function testSm2SignVerify() { - /* Generate a key. */ - await publicGenKeyFunc(generateKeyAlias, genrateKeyOptions); - - /* Generate a signature. */ - let signHandle; - let signFinishOutData; - await publicInitFunc(generateKeyAlias, signOptions); - - signHandle = handle; - signOptions.inData = StringToUint8Array(signVerifyInData) - await publicUpdateFunc(signHandle, signOptions); - - signOptions.inData = new Uint8Array(new Array()); - await publicFinishFunc(signHandle, signOptions); - signFinishOutData = finishOutData; - - /* Export the key. */ - await publicExportKeyFunc(generateKeyAlias, genrateKeyOptions); +``` - /* Import the key. */ - verifyOptions.inData = exportKey; - await publicImportKeyFunc(importKeyAlias, verifyOptions); +## Key Access Control - /* Verify the signature. */ - let verifyHandle; - await publicInitFunc(importKeyAlias, verifyOptions); +The HUKS provides comprehensive key access control to prevent unauthorized access. - verifyHandle = handle; +Services can access only their own keys, that is, the keys generated or imported through HUKS. +In 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. +The 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. - verifyOptions.inData = StringToUint8Array(signVerifyInData) - await publicUpdateFunc(verifyHandle, verifyOptions); +**User Identity Authentication** - verifyOptions.inData = signFinishOutData; - await publicFinishFunc(verifyHandle, verifyOptions); +When generating or importing a key, you can enable user identity authentication for the key use. 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. - await publicDeleteKeyFunc(generateKeyAlias, genrateKeyOptions); - await publicDeleteKeyFunc(importKeyAlias, genrateKeyOptions); -} +In addition to user identity authentication, the authorized key access type (key expiration condition) must be either of the following types: +- Invalidate the key when the screen lock password is cleared.
This type 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. Use this type for user-related data protection or access based on screen lock passwords. +- Invalidate the key when new biometric enrollments are added.
This type 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. You can use this type for scenarios, such as password-free login or payment. -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testSm2SignVerify') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testSm2SignVerify(); - }) - } - .width('100%') - .height('100%') - } -} -``` +To ensure the validity of the user authentication result, the HUKS supports challenge value verification. Before user identity authentication, obtain the challenge (in the [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](../reference/apis/js-apis-useriam-userauth.md#authinstance9). The challenge value of the authentication token is then verified during key operations. -### Key Agreement +**How to Develop** -Two or more objects communicate with each other based on the same session key. +If secondary user identity authentication is enabled for a key, initialize the key session and obtain the challenge value. Then, pass the challenge value 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. -The development procedure is as follows: +![huks_key_user_auth_work_flow](./figures/huks_key_user_auth_work_flow.png) -1. Generate two keys. -2. Export the keys separately. -3. Perform key agreement. +**Available APIs** -**Supported key types**: +1. [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 attribute set are mandatory for key generation/import. -The **HksInit()** and **HksFinish()** APIs have requirements on **paramSet**. The **HksUpdate()** API has no requirements on **paramSet**. + **Table 3** User authentication types + + | Name | Value | Description | + | ------------------------------- |---|------------------------ | + | HUKS_USER_AUTH_TYPE_FINGERPRINT |0x0001 | Fingerprint authentication. | + | HUKS_USER_AUTH_TYPE_FACE |0x0002 | Facial authentication. | +| HUKS_USER_AUTH_TYPE_PIN |0x0004 | PIN authentication. | + + > **NOTE** + > + > You can specify any or a combination of the three authentication types. + -Requirements of **HksInit()** for **paramSet**: +**Table 4** Secure access types -| HUKS_ALG_ALGORITHM | HUKS_ALG_KEY_SIZE | HUKS_ALG_PURPOSE | -| ------------------ | ------------------------------------------------------------ | ---------------------- | -| HUKS_ALG_ECDH | HUKS_ECC_KEY_SIZE_224, HUKS_ECC_KEY_SIZE_256, HUKS_ECC_KEY_SIZE_384, HUKS_ECC_KEY_SIZE_521| HUKS_KEY_PURPOSE_AGREE | -| HUKS_ALG_DH | HUKS_DH_KEY_SIZE_2048, HUKS_DH_KEY_SIZE_3072, HUKS_DH_KEY_SIZE_4096| HUKS_KEY_PURPOSE_AGREE | -| HUKS_ALG_X25519 | HUKS_CURVE25519_KEY_SIZE_256 | HUKS_KEY_PURPOSE_AGREE | +| Name | Value | Description | +| --------------------------------------- | ----- | ------------------------------------------------------------ | +| HUKS_AUTH_ACCESS_INVALID_CLEAR_PASSWORD | 1 | Invalidates the key after the screen lock password is cleared. | +| 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. | +| | | | -Requirements of **HksFinish()** for **paramSet**: +> **NOTE** + > + > **HUKS_AUTH_ACCESS_INVALID_CLEAR_PASSWORD** and **HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL** are mutually exclusive. -The derived key is used as a symmetric key. +**Table 5** Challenge types -| HUKS_TAG_KEY_STORAGE_FLAG | HUKS_TAG_KEY_ALIAS | HUKS_TAG_IS_KEY_ALIAS | HUKS_TAG_ALGORITHM | HUKS_TAG_KEY_SIZE | HUKS_TAG_PURPOSE | HUKS_TAG_PADDING | HUKS_TAG_DIGEST | HUKS_TAG_BLOCK_MODE | -| ------------------------------ | ------------------ | --------------------- | ------------------ | ------------------------------------------------------------ | -------------------------------------------------- | ------------------ | ------------------------------------------------------------ | ------------------------------------------- | -| **HUKS_STORAGE_TEMP** or not set| Not required | TRUE | Not required | Not required | Not required | Not required | Not required | Not required | -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_AES | HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256| HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT| HUKS_PADDING_PKCS7 | Optional | HUKS_MODE_CCM HUKS_MODE_GCM HUKS_MODE_CTP | -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_AES | HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256| HUKS_KEY_PURPOSE_DERIVE | Optional | HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512 | Optional | -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_HMAC | Multiple of 8, in bits | HUKS_KEY_PURPOSE_MAC | Optional | HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| Optional | +| Name | Value | Description | +| ------------------------------- | ---- | ------------------------------ | +| HUKS_CHALLENGE_TYPE_NORMAL | 0 | Normal challenge, which requires an independent user authentication for each use of the key.| +| HUKS_CHALLENGE_TYPE_CUSTOM | 1 | Custom challenge, which supports only one user authentication for multiple keys.| +| HUKS_CHALLENGE_TYPE_NONE | 2 | No challenge is required during user authentication.| -> **NOTE**
+> **NOTICE** > -> The length of the key after agreement (converted into bits) must be greater than or equal to the selected **HUKS_TAG_KEY_SIZE**. +> The three challenge types are mutually exclusive. > -> The key alias cannot exceed 64 bytes. +> If the challenge type is **HUKS_CHALLENGE_TYPE_NONE**, no challenge is required. However, the key can be accessed only 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. -Before you get started, understand the following variables: -| Parameter | Type | Mandatory| Description | -| ------------------- | ----------- | ---- | -------------------------------------- | -| srcKeyAliasFirst | string | Yes | Alias of the key generated. | -| srcKeyAliasSecond | string | Yes | Alias of key 2 generated. | -| huksOptions | HuksOptions | Yes | Tags required for generating the key. | -| finishOptionsFrist | HuksOptions | Yes | Tags required for key agreement. | -| finishOptionsSecond | HuksOptions | Yes | Tags required for key agreement.| +2. To 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. + **Table 6** APIs for using a key + +| API | Description | + | -------------------------------------- | ----------------------------| + |initSession(keyAlias: string, options: HuksOptions, callback: AsyncCallback\) : void| Initializes the key session and obtains the challenge value.| + |updateSession(handle: number, options: HuksOptions, token: Uint8Array, callback: AsyncCallback\) : void| Operates data by segment and passes the authentication token.| + |finishSession(handle: number, options: HuksOptions, token: Uint8Array, callback: AsyncCallback\) : void| Finalizes the key session.| + -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). -**Example** +**How to Develop** +1. Generate a key and specify user authentication attributes. ```ts -/* The agree() operation supports ECDH, DH, and X25519 keys. - * - * The following uses the Promise() operation of an X25519 256-bit TEMP key as an example. - */ import huks from '@ohos.security.huks'; -function StringToUint8Array(str) { - let arr = []; - for (let i = 0, j = str.length; i < j; ++i) { - arr.push(str.charCodeAt(i)); - } - return new Uint8Array(arr); -} - -async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); - try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let keyAlias = 'dh_key_fingerprint_access'; +let properties = new Array(); +properties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM4, } - -async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback doInit`); - try { - await initSession(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback1: doInit success, data = ${JSON.stringify(data)}`); - handle = data.handle; - }) - .catch((error) => { - console.error(`callback1: doInit failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); - } +properties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, } - -function initSession(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.initSession(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +properties[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, } - -async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { - console.info(`enter callback doUpdate`); - try { - await updateSession(handle, huksOptions) - .then ((data) => { - console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); - } +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC, } - -function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.updateSession(handle, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +properties[4] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, } - -async function publicFinishFunc(handle:number, huksOptions:huks.HuksOptions) { - console.info(`enter callback doFinish`); - try { - await finishSession(handle, huksOptions) - .then ((data) => { - console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); - } +// Enable fingerprint authentication. +properties[5] = { + tag: huks.HuksTag.HUKS_TAG_USER_AUTH_TYPE, + value: huks.HuksUserAuthType.HUKS_USER_AUTH_TYPE_FINGERPRINT } - -function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.finishSession(handle, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +// Set the key expiration type. Invalidate the key when a new biometric feature (fingerprint) is enrolled. +properties[6] = { + tag: huks.HuksTag.HUKS_TAG_KEY_AUTH_ACCESS_TYPE, + value: huks.HuksAuthAccessType.HUKS_AUTH_ACCESS_INVALID_NEW_BIO_ENROLL } - -async function publicExportKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback export`); - try { - await exportKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: exportKeyItem success, data = ${JSON.stringify(data)}`); - exportKey = data.outData; - }) - .catch(error => { - console.error(`callback: exportKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: exportKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } +// Use the default challenge type. +properties[7] = { + tag: huks.HuksTag.HUKS_TAG_CHALLENGE_TYPE, + value: huks.HuksChallengeType.HUKS_CHALLENGE_TYPE_NORMAL } - -function exportKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.exportKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +let huksOptions = { + properties: properties, + inData: new Uint8Array(new Array()) } -async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); +/* + * Generate a key. + */ +function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { + return new Promise((resolve, reject) => { try { - await deleteKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -let srcKeyAliasFirst = "AgreeX25519KeyFirstAlias"; -let srcKeyAliasSecond = "AgreeX25519KeySecondAlias"; -let agreeX25519InData = 'AgreeX25519TestIndata'; -let handle; -let exportKey; -let exportKeyFrist; -let exportKeySecond; - -async function testAgree() { - /* Configure the parameters for generating the key. */ - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_X25519, - } - 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_CURVE25519_KEY_SIZE_256, - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, - } - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - properties[5] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_CBC, - } - let HuksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) - } - - /* 1. Generate two keys and export them. */ - await publicGenKeyFunc(srcKeyAliasFirst, HuksOptions); - await publicGenKeyFunc(srcKeyAliasSecond, HuksOptions); - - await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions); - exportKeyFrist = exportKey; - await publicExportKeyFunc(srcKeyAliasFirst, HuksOptions); - exportKeySecond = exportKey; - - /* Configure parameters for the first key agreement. */ - let finishProperties = new Array(); - finishProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, - value: huks.HuksKeyStorageType.HUKS_STORAGE_TEMP, - } - finishProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, - value: true - } - finishProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES, - } - finishProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, - } - finishProperties[4] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, - } - finishProperties[5] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, - } - finishProperties[6] = { - tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, - value: StringToUint8Array(srcKeyAliasFirst+ 'final'), - } - finishProperties[7] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - finishProperties[8] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_ECB, - } - let finishOptionsFrist = { - properties: finishProperties, - inData: StringToUint8Array(agreeX25519InData) - } - - /* Obtain the first agreed key. */ - await publicInitFunc(srcKeyAliasFirst, HuksOptions); - HuksOptions.inData = exportKeySecond; - await publicUpdateFunc(handle, HuksOptions); - await publicFinishFunc(handle, finishOptionsFrist); - - /* Configure parameters for the second key agreement. */ - let finishOptionsSecond = { - properties: finishProperties, - inData: StringToUint8Array(agreeX25519InData) - } - finishOptionsSecond.properties.splice(6, 1, { - tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, - value: StringToUint8Array(srcKeyAliasSecond + 'final'), - }) - - /* Obtain the second agreed key. */ - await publicInitFunc(srcKeyAliasSecond, HuksOptions); - HuksOptions.inData = exportKeyFrist; - await publicUpdateFunc(handle, HuksOptions); - await publicFinishFunc(handle, finishOptionsSecond); - - - await publicDeleteKeyFunc(srcKeyAliasFirst, HuksOptions); - await publicDeleteKeyFunc(srcKeyAliasSecond, HuksOptions); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testAgree') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testAgree(); - }) - } - .width('100%') - .height('100%') - } -} -``` - -### Key Derivation - -Derive one or more keys from a key. - -The development procedure is as follows: - -1. Generate a key. -2. Derive a key. - -**Supported key types**: - -The **HksInit()** and **HksFinish()** APIs have requirements on **paramSet**. The **HksUpdate()** API has no requirements on **paramSet**. - -Requirements of **HksInit()** for **paramSet**: - -| HUKS_TAG_ALGORITHM | HUKS_TAG_PURPOSE | HUKS_TAG_DIGEST | HUKS_TAG_DERIVE_KEY_SIZE | -| ------------------------------------------------------------ | ----------------------- | ---------------------------------------------------------- | ------------------------ | -| HUKS_ALG_HKDF (supported key lengths: HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256)| HUKS_KEY_PURPOSE_DERIVE | HUKS_DIGEST_SHA256 HUKS_DIGEST_SHA384 HUKS_DIGEST_SHA512 | Mandatory | -| HUKS_ALG_PBKDF2 (supported key lengths: HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256)| HUKS_KEY_PURPOSE_DERIVE | HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| Mandatory | - -Requirements of **HksFinish()** for **paramSet**: - -The derived key is used as a symmetric key. - -| HUKS_TAG_KEY_STORAGE_FLAG | HUKS_TAG_KEY_ALIAS | HUKS_TAG_IS_KEY_ALIAS | HUKS_TAG_ALGORITHM | HUKS_TAG_KEY_SIZE | HUKS_TAG_PURPOSE | HUKS_TAG_PADDING | HUKS_TAG_DIGEST | HUKS_TAG_BLOCK_MODE | -| ------------------------------ | ------------------ | --------------------- | ------------------ | ------------------------------------------------------------ | -------------------------------------------------- | ------------------------------------- | ------------------------------------------------------------ | ------------------------------------------- | -| **HUKS_STORAGE_TEMP** or not set| Not required | TRUE | Not required | Not required | Not required | Not required | Not required | Not required | -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_AES | HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256| HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT| HUKS_PADDING_NONE, HUKS_PADDING_PKCS7| Optional | HUKS_MODE_CBC HUKS_MODE_ECB | -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_AES | HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256| HUKS_KEY_PURPOSE_ENCRYPT or HUKS_KEY_PURPOSE_DECRYPT| HUKS_PADDING_NONE | Optional | HUKS_MODE_CCM, HUKS_MODE_GCM, HUKS_MODE_CTR| -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_AES | HUKS_AES_KEY_SIZE_128, HUKS_AES_KEY_SIZE_192, HUKS_AES_KEY_SIZE_256| HUKS_KEY_PURPOSE_DERIVE | Optional | HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512 | Optional | -| HUKS_STORAGE_PERSISTENT | (Mandatory) Maximum 64 bytes.| TRUE | HUKS_ALG_HMAC | Multiple of 8, in bits | HUKS_KEY_PURPOSE_MAC | Optional | HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| Optional | - -> **NOTE**
-> -> The length of the derived key (converted into bits) must be greater than or equal to the selected **HUKS_TAG_KEY_SIZE**. -> -> The key alias cannot exceed 64 bytes. - -Before you get started, understand the following variables: - -| Parameter | Type | Mandatory| Description | -| ------------- | ----------- | ---- | ---------------- | -| srcKeyAlias | string | Yes | Alias of the key generated. | -| huksOptions | HuksOptions | Yes | Parameters for generating the key.| -| finishOptions | HuksOptions | Yes | Parameters for deriving a key.| - -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). - -**Example** - -```ts -/*The derive() operation supports HKDF and pbdkf keys. - * - * The following uses the Promise() operation of an HKDF256 key as an example. - */ -import huks from '@ohos.security.huks'; - -function StringToUint8Array(str) { - let arr = []; - for (let i = 0, j = str.length; i < j; ++i) { - arr.push(str.charCodeAt(i)); - } - return new Uint8Array(arr); -} - -async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); - try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter promise doInit`); - try { - await huks.initSession(keyAlias, huksOptions) - .then ((data) => { - console.info(`promise: doInit success, data = ${JSON.stringify(data)}`); - handle = data.handle; - }) - .catch(error => { - console.error(`promise: doInit key failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`promise: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { - console.info(`enter callback doUpdate`); - try { - await updateSession(handle, huksOptions) - .then ((data) => { - console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.updateSession(handle, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicFinishFunc(handle:number, huksOptions:huks.HuksOptions) { - console.info(`enter callback doFinish`); - try { - await finishSession(handle, huksOptions) - .then ((data) => { - console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.finishSession(handle, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); - try { - await deleteKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -let deriveHkdfInData = "deriveHkdfTestIndata"; -let srcKeyAlias = "deriveHkdfKeyAlias"; -let handle; -let HuksKeyDeriveKeySize = 32; - -async function testDerive() { - /* Configure the parameters for generating the key. */ - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES, - } - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DERIVE, - } - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256, - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128, - } - let huksOptions = { - properties: properties, - inData: new Uint8Array(new Array()) - } - - /* Generate a key. */ - await publicGenKeyFunc(srcKeyAlias, huksOptions); - - /* Modify the parameter set for init(). */ - huksOptions.properties.splice(0, 1, { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_HKDF, - }); - huksOptions.properties.splice(3, 1, { - tag: huks.HuksTag.HUKS_TAG_DERIVE_KEY_SIZE, - value: HuksKeyDeriveKeySize, - }); - - let finishProperties = new Array(); - finishProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, - value: huks.HuksKeyStorageType.HUKS_STORAGE_PERSISTENT, - } - finishProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_IS_KEY_ALIAS, - value: true, - } - finishProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES, - } - finishProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, - } - finishProperties[4] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | - huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, - } - finishProperties[5] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_NONE, - } - finishProperties[6] = { - tag: huks.HuksTag.HUKS_TAG_KEY_ALIAS, - value: StringToUint8Array(srcKeyAlias), - } - finishProperties[7] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_NONE, - } - finishProperties[8] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_ECB, - } - let finishOptions = { - properties: finishProperties, - inData: new Uint8Array(new Array()) - } - - /* Derive a key. */ - await publicInitFunc(srcKeyAlias, huksOptions); - - huksOptions.inData = StringToUint8Array(deriveHkdfInData); - await publicUpdateFunc(handle, huksOptions); - await publicFinishFunc(handle, finishOptions); - - huksOptions.properties.splice(0, 1, { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_AES, - }); - huksOptions.properties.splice(3, 1, { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_128, - }); - - await publicDeleteKeyFunc(srcKeyAlias, huksOptions); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testDerive') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testDerive(); - }) - } - .width('100%') - .height('100%') - } -} -``` - -### Key MAC - -A message authentication code (MAC) is a hash-based value used for authenticating a message. It is used to check whether the message comes from the stated sender and has not been changed. - -The development procedure is as follows: - -1. Generate a key. -2. Generate a MAC. - -**Supported key types**: - -Only **HksInit()** has requirements on parameters in **paramSet**. The other Init-Update-Finish APIs have no requirements on **paramSet**. - -| HUKS_TAG_ALGORITHM | HUKS_TAG_KEY_SIZE | HUKS_TAG_PURPOSE | HUKS_TAG_DIGEST | HUKS_TAG_PADDING | HUKS_TAG_BLOCK_MODE | -| ------------ | ---------- | ------------------- | ------------------------------------------------------------ | ---------- | ---------- | -| HUKS_ALG_HMAC | Optional| HUKS_KEY_PURPOSE_MAC | HUKS_DIGEST_SHA1, HUKS_DIGEST_SHA224, HUKS_DIGEST_SHA256, HUKS_DIGEST_SHA384, HUKS_DIGEST_SHA512| Optional| Optional| -| HUKS_ALG_SM3 | Optional| HUKS_KEY_PURPOSE_MAC | HUKS_DIGEST_SM3 | Optional| Optional| - -> **NOTE**
-> -> The key alias cannot exceed 64 bytes. - -Before you get started, understand the following variables: - -| Parameter | Type | Mandatory| Description | -| ----------- | ----------- | ---- | -------------- | -| srcKeyAlias | string | Yes | Alias of the key generated.| -| huksOptions | HuksOptions | Yes | Key parameter set. | - -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). - -**Example** - -```ts -/*The mac() operation supports HMAC and SM3 keys. - * - * The following uses the Promise() operation of an SM3 256-bit key as an example. - */ -import huks from '@ohos.security.huks'; - -function StringToUint8Array(str) { - let arr = []; - for (let i = 0, j = str.length; i < j; ++i) { - arr.push(str.charCodeAt(i)); - } - return new Uint8Array(arr); -} - -async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); - try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback doInit`); - try { - await initSession(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback1: doInit success, data = ${JSON.stringify(data)}`); - handle = data.handle; - }) - .catch((error) => { - console.error(`callback1: doInit failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function initSession(keyAlias:string, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.initSession(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicUpdateFunc(handle:number, huksOptions:huks.HuksOptions) { - console.info(`enter callback doUpdate`); - try { - await updateSession(handle, huksOptions) - .then ((data) => { - console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function updateSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.updateSession(handle, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicFinishFunc(handle:number, huksOptions:huks.HuksOptions) { - console.info(`enter callback doFinish`); - try { - await finishSession(handle, huksOptions) - .then ((data) => { - console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function finishSession(handle:number, huksOptions:huks.HuksOptions) : Promise { - return new Promise((resolve, reject) => { - try { - huks.finishSession(handle, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); - try { - await deleteKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); -} - -let srcKeyAlias = "sm3KeyAlias"; -let hmacInData = 'sm3TestIndata'; -let handle; - -async function testMac() { - /* Configure the parameters for generating the key. */ - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_SM3, - } - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_MAC, - } - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SM3, - } - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, - } - let huksOptions = { - properties:properties, - inData:new Uint8Array(new Array()) - } - - /* Generate a key. */ - await publicGenKeyFunc(srcKeyAlias, huksOptions); - - /* Modify the parameter set for init() and perform the mac operation. */ - huksOptions.properties.splice(3, 3); - await publicInitFunc(srcKeyAlias, huksOptions); - huksOptions.inData = StringToUint8Array(hmacInData); - await publicUpdateFunc(handle, huksOptions); - huksOptions.inData = new Uint8Array(new Array()); - await publicFinishFunc(handle, huksOptions); - - huksOptions.properties.splice(1, 0, { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, - }); - await publicDeleteKeyFunc(srcKeyAlias, huksOptions); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testMac') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testMac(); - }) + huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); } - .width('100%') - .height('100%') + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); } + }); } -``` - -### AttestID - -After an application generates an asymmetric key, the certificate chain can be obtained through ID attestation. ID attestation supports the following device: brand, device, product, serial number, IMEI, MEID, manufacturer, model, SOC ID, and UDID. - -The application can also obtain the certificate chain through key attestation. - -ID attestation and key attestation are available only for devices in a trusted execution Environment (TEE). - -The development procedure is as follows: -1. Generate a certificate. -2. Obtain certificate information. - -**Supported key types**: - -RSA512, RSA768, RSA1024, RSA2048, RSA3072, RSA4096, ECC224, ECC256, ECC384, ECC521, X25519 - -> **NOTE**
-> -> The key alias cannot exceed 64 bytes. - -Before you get started, understand the following variables: - -| Parameter | Type | Mandatory| Description | -| -------- | ----------- | ---- | ------------------------------------ | -| keyAlias | string | Yes | Alias of the key. The certificate to be obtained stores the key.| -| options | HuksOptions | Yes | Parameters and data required for obtaining the certificate. | +async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback generateKeyItem`); + let throwObject = {isThrow: false}; + try { + await generateKeyItem(keyAlias, huksOptions, throwObject) + .then((data) => { + console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + } +} -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). +async function TestGenKeyForFingerprintAccessControl() { + await publicGenKeyFunc(keyAlias, huksOptions); +} +``` -**Example** +2. Initialize the key session to obtain a challenge, and initiate fingerprint authentication to obtain an authentication token. ```ts -/* The following is an example of ID attestation. */ import huks from '@ohos.security.huks'; +import userIAM_userAuth from '@ohos.userIAM.userAuth'; -function StringToUint8Array(str) { - let arr = []; - for (let i = 0, j = str.length; i < j; ++i) { - arr.push(str.charCodeAt(i)); - } - return new Uint8Array(arr); +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let srcKeyAlias = 'sm4_key_fingerprint_access'; +let handle; +let challenge; +let fingerAuthToken; +let authType = userIAM_userAuth.UserAuthType.FINGERPRINT; +let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1; + +/* Configure the key generation parameter set and key encryption parameter set. */ +let properties = new Array(); +properties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM4, +} +properties[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, +} +properties[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, +} +properties[3] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC, +} +properties[4] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +let huksOptions = { + properties: properties, + inData: new Uint8Array(new Array()) } -async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); +function initSession(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise { + return new Promise((resolve, reject) => { try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); + huks.initSession(keyAlias, huksOptions, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + throwObject.isThrow = true; + throw(error); } + }); } -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); +async function publicInitFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback doInit`); + let throwObject = {isThrow: false}; + try { + await initSession(keyAlias, huksOptions, throwObject) + .then ((data) => { + console.info(`callback: doInit success, data = ${JSON.stringify(data)}`); + handle = data.handle; + challenge = data.challenge; + }) + .catch((error) => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doInit failed, code: ${error.code}, msg: ${error.message}`); } + }); + } catch (error) { + console.error(`callback: doInit input arg invalid, code: ${error.code}, msg: ${error.message}`); + } +} + +function userIAMAuthFinger(huksChallenge:Uint8Array) { + // Obtain an authentication object. + let auth; + try { + auth = userIAM_userAuth.getAuthInstance(huksChallenge, authType, authTrustLevel); + console.log("get auth instance success"); + } catch (error) { + console.log("get auth instance failed" + error); + } + + // Subscribe to the authentication result. + try { + auth.on("result", { + callback: (result: userIAM_userAuth.AuthResultInfo) => { + /* The authentication is successful, and the authentication token is obtained. */ + fingerAuthToken = result.token; + } }); + console.log("subscribe authentication event success"); + } catch (error) { + console.log("subscribe authentication event failed " + error); + } + + // Start user authentication. + try { + auth.start(); + console.info("authV9 start auth success"); + } catch (error) { + console.info("authV9 start auth failed, error = " + error); + } +} + +async function testInitAndAuthFinger() { + /* Initialize the key session to obtain a challenge. */ + await publicInitFunc(srcKeyAlias, huksOptions); + /* Invoke userIAM to perform user identity authentication. */ + userIAMAuthFinger(challenge); } +``` -async function publicAttestKey(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback attestKeyItem`); - try { - await attestKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: attestKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: attestKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: attestKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } +3. Pass in the authentication token to perform data operations. +```ts +/* + * The following uses an SM4 128-bit key and callback-based APIs as an example. + */ +import huks from '@ohos.security.huks'; + +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let srcKeyAlias = 'sm4_key_fingerprint_access'; +let IV = '1234567890123456'; +let cipherInData = 'Hks_SM4_Cipher_Test_101010101010101010110_string'; +let handle; +let fingerAuthToken; +let updateResult = new Array(); +let finishOutData; + +/* Configure the key generation parameter set and key encryption parameter set. */ +let propertiesEncrypt = new Array(); +propertiesEncrypt[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_SM4, +} +propertiesEncrypt[1] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT, +} +propertiesEncrypt[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_SM4_KEY_SIZE_128, +} +propertiesEncrypt[3] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_NONE, +} +propertiesEncrypt[4] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_CBC, +} +propertiesEncrypt[5] = { + tag: huks.HuksTag.HUKS_TAG_IV, + value: StringToUint8Array(IV), +} +let encryptOptions = { + properties: propertiesEncrypt, + inData: new Uint8Array(new Array()) } -function attestKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise{ - return new Promise((resolve, reject) => { - try { - huks.attestKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +function StringToUint8Array(str) { + let arr = []; + for (let i = 0, j = str.length; i < j; ++i) { + arr.push(str.charCodeAt(i)); + } + return new Uint8Array(arr); } -async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); +function updateSession(handle:number, huksOptions:huks.HuksOptions, token:Uint8Array, throwObject) : Promise { + return new Promise((resolve, reject) => { try { - await deleteKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); + huks.updateSession(handle, huksOptions, token, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); + } + }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } + throwObject.isThrow = true; + throw(error); + } + }); +} + +async function publicUpdateFunc(handle:number, token:Uint8Array, huksOptions:huks.HuksOptions) { + console.info(`enter callback doUpdate`); + let throwObject = {isThrow: false}; + try { + await updateSession(handle, huksOptions, token, throwObject) + .then ((data) => { + console.info(`callback: doUpdate success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doUpdate failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: doUpdate input arg invalid, code: ${error.code}, msg: ${error.message}`); + } } -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); +function finishSession(handle:number, huksOptions:huks.HuksOptions, token:Uint8Array, throwObject) : Promise { + return new Promise((resolve, reject) => { + try { + huks.finishSession(handle, huksOptions, token, function (error, data) { + if (error) { + reject(error); + } else { + resolve(data); } - }); + }); + } catch (error) { + throwObject.isThrow = true; + throw(error); + } + }); +} + +async function publicFinishFunc(handle:number, token:Uint8Array, huksOptions:huks.HuksOptions) { + console.info(`enter callback doFinish`); + let throwObject = {isThrow: false}; + try { + await finishSession(handle, huksOptions, token, throwObject) + .then ((data) => { + finishOutData = data.outData; + console.info(`callback: doFinish success, data = ${JSON.stringify(data)}`); + }) + .catch(error => { + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: doFinish failed, code: ${error.code}, msg: ${error.message}`); + } + }); + } catch (error) { + console.error(`callback: doFinish input arg invalid, code: ${error.code}, msg: ${error.message}`); + } } -let securityLevel = StringToUint8Array('sec_level'); -let challenge = StringToUint8Array('challenge_data'); -let versionInfo = StringToUint8Array('version_info'); -let udid = StringToUint8Array('udid'); -let serial = StringToUint8Array('serial'); -let deviceId = StringToUint8Array('device_id'); -let idAliasString = "id attest"; - -async function testAttestId() { - let aliasString = idAliasString; - let aliasUint8 = StringToUint8Array(aliasString); - - /* Configure parameters and generate a key. */ - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_RSA - }; - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, - value: huks.HuksKeyStorageType.HUKS_STORAGE_PERSISTENT - }; - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_2048 - }; - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY - }; - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - }; - properties[5] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_PSS - }; - properties[6] = { - tag: huks.HuksTag.HUKS_TAG_KEY_GENERATE_TYPE, - value: huks.HuksKeyGenerateType.HUKS_KEY_GENERATE_TYPE_DEFAULT - }; - properties[7] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_ECB - }; - let options = { - properties: properties - }; - await publicGenKeyFunc(aliasString, options); - - /* Configure the certificate parameter set. */ - let attestProperties = new Array(); - attestProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO, - value: securityLevel - }; - attestProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_CHALLENGE, - value: challenge - }; - attestProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_VERSION_INFO, - value: versionInfo - }; - attestProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_ALIAS, - value: aliasUint8 - }; - attestProperties[4] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_UDID, - value: udid - }; - attestProperties[5] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_SERIAL, - value: serial - }; - attestProperties[6] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_DEVICE, - value: deviceId - }; - let huksOptions = { - properties: attestProperties - }; - - await publicAttestKey(aliasString, huksOptions); - - await publicDeleteKeyFunc(aliasString, options); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testAttestId') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testAttestId(); - }) - } - .width('100%') - .height('100%') - } +async function testSm4Cipher() { + encryptOptions.inData = StringToUint8Array(cipherInData); + /* Pass in the authentication token. */ + await publicUpdateFunc(handle, fingerAuthToken, encryptOptions); + encryptUpdateResult = updateResult; + + encryptOptions.inData = new Uint8Array(new Array()); + /* Pass in the authentication token. */ + await publicFinishFunc(handle, fingerAuthToken, encryptOptions); + if (finishOutData === cipherInData) { + console.info('test finish encrypt err '); + } else { + console.info('test finish encrypt success'); + } } ``` -### AttestKey - -After an application generates an asymmetric key, the certificate chain can be obtained by key attestation. You can also use ID attestation to obtain the certificate chain. The public certificate contains information such as the device ID. - -ID attestation and key attestation are available only for devices in a trusted execution Environment (TEE). - -The development procedure is as follows: +## Key Attestation -1. Generate a certificate. -2. Obtain certificate information. +The 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. -**Supported key types**: +**How to Develop** +1. Pass in the key alias and the attribute tag of the key to be attested. +2. 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. +3. 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. -RSA512, RSA768, RSA1024, RSA2048, RSA3072, RSA4096, ECC224, ECC256, ECC384, ECC521, X25519 +**Available APIs** -> **NOTE**
-> -> The key alias cannot exceed 64 bytes. +**Table 7** APIs for key attestation +| API | Description | +| -------------------------------------- | ----------------------------| +|attestKeyItem(keyAlias: string, options: HuksOptions, callback: AsyncCallback\) : void| Attests a key.| -Before you get started, understand the following variables: +**How to Develop** -| Parameter | Type | Mandatory| Description | -| -------- | ----------- | ---- | ------------------------------------ | -| keyAlias | string | Yes | Alias of the key. The certificate to be obtained stores the key.| -| options | HuksOptions | Yes | Parameters and data required for obtaining the certificate. | +```ts +/* + * Attest a key and return the result in a callback. + */ +import huks from '@ohos.security.huks'; -For details about the APIs, see [HUKS](../reference/apis/js-apis-huks.md). +/* + * Determine the key alias and encapsulate the key attribute set. + */ +let keyAliasString = "key attest"; +let aliasString = keyAliasString; +let aliasUint8 = StringToUint8Array(keyAliasString); +let securityLevel = StringToUint8Array('sec_level'); +let challenge = StringToUint8Array('challenge_data'); +let versionInfo = StringToUint8Array('version_info'); +let attestCertChain; -**Example** +let genKeyProperties = new Array(); +genKeyProperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ALGORITHM, + value: huks.HuksKeyAlg.HUKS_ALG_RSA +}; +genKeyProperties[1] = { + tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, + value: huks.HuksKeyStorageType.HUKS_STORAGE_PERSISTENT +}; +genKeyProperties[2] = { + tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, + value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_2048 +}; +genKeyProperties[3] = { + tag: huks.HuksTag.HUKS_TAG_PURPOSE, + value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY +}; +genKeyProperties[4] = { + tag: huks.HuksTag.HUKS_TAG_DIGEST, + value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 +}; +genKeyProperties[5] = { + tag: huks.HuksTag.HUKS_TAG_PADDING, + value: huks.HuksKeyPadding.HUKS_PADDING_PSS +}; +genKeyProperties[6] = { + tag: huks.HuksTag.HUKS_TAG_KEY_GENERATE_TYPE, + value: huks.HuksKeyGenerateType.HUKS_KEY_GENERATE_TYPE_DEFAULT +}; +genKeyProperties[7] = { + tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, + value: huks.HuksCipherMode.HUKS_MODE_ECB +}; +let genOptions = { + properties: genKeyProperties +}; -```ts -/* The following is an example of AttestKey. */ -import huks from '@ohos.security.huks'; +let attestKeyproperties = new Array(); +attestKeyproperties[0] = { + tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO, + value: securityLevel +}; +attestKeyproperties[1] = { + tag: huks.HuksTag.HUKS_TAG_ATTESTATION_CHALLENGE, + value: challenge +}; +attestKeyproperties[2] = { + tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_VERSION_INFO, + value: versionInfo +}; +attestKeyproperties[3] = { + tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_ALIAS, + value: aliasUint8 +}; +let huksOptions = { + properties: attestKeyproperties +}; function StringToUint8Array(str) { let arr = []; @@ -3477,22 +2595,7 @@ function StringToUint8Array(str) { return new Uint8Array(arr); } -async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback generateKeyItem`); - try { - await generateKeyItem(keyAlias, huksOptions) - .then((data) => { - console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); - }) - .catch(error => { - console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); - }); - } catch (error) { - console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); - } -} - -function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { +function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) { return new Promise((resolve, reject) => { try { huks.generateKeyItem(keyAlias, huksOptions, function (error, data) { @@ -3503,27 +2606,33 @@ function generateKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -async function publicAttestKey(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback attestKeyItem`); +async function publicGenKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback generateKeyItem`); + let throwObject = {isThrow: false}; try { - await attestKeyItem(keyAlias, huksOptions) - .then ((data) => { - console.info(`callback: attestKeyItem success, data = ${JSON.stringify(data)}`); + await generateKeyItem(keyAlias, huksOptions, throwObject) + .then((data) => { + console.info(`callback: generateKeyItem success, data = ${JSON.stringify(data)}`); }) .catch(error => { - console.error(`callback: attestKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: generateKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: attestKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: generateKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function attestKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise{ +function attestKeyItem(keyAlias:string, huksOptions:huks.HuksOptions, throwObject) : Promise{ return new Promise((resolve, reject) => { try { huks.attestKeyItem(keyAlias, huksOptions, function (error, data) { @@ -3534,136 +2643,49 @@ function attestKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) : Promise< } }); } catch (error) { + throwObject.isThrow = true; throw(error); } }); } -async function publicDeleteKeyFunc(keyAlias:string, huksOptions:huks.HuksOptions) { - console.info(`enter callback deleteKeyItem`); +async function publicAttestKey(keyAlias:string, huksOptions:huks.HuksOptions) { + console.info(`enter callback attestKeyItem`); + let throwObject = {isThrow: false}; try { - await deleteKeyItem(keyAlias, huksOptions) + await attestKeyItem(keyAlias, huksOptions, throwObject) .then ((data) => { - console.info(`callback: deleteKeyItem key success, data = ${JSON.stringify(data)}`); + console.info(`callback: attestKeyItem success, data = ${JSON.stringify(data)}`); + if (data !== null && data.certChains !== null) { + attestCertChain = data.certChains; + } }) .catch(error => { - console.error(`callback: deleteKeyItem failed, code: ${error.code}, msg: ${error.message}`); + if (throwObject.isThrow) { + throw(error); + } else { + console.error(`callback: attestKeyItem failed, code: ${error.code}, msg: ${error.message}`); + } }); } catch (error) { - console.error(`callback: deleteKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); + console.error(`callback: attestKeyItem input arg invalid, code: ${error.code}, msg: ${error.message}`); } } -function deleteKeyItem(keyAlias:string, huksOptions:huks.HuksOptions) { - return new Promise((resolve, reject) => { - try { - huks.deleteKeyItem(keyAlias, huksOptions, function (error, data) { - if (error) { - reject(error); - } else { - resolve(data); - } - }); - } catch (error) { - throw(error); - } - }); +async function AttestKeyTest() { + await publicGenKeyFunc(aliasString, genOptions); + + await publicAttestKey(aliasString, huksOptions); + console.info('attest certChain data: ' + attestCertChain) } +``` -let securityLevel = StringToUint8Array('sec_level'); -let challenge = StringToUint8Array('challenge_data'); -let versionInfo = StringToUint8Array('version_info'); -let keyAliasString = "key attest"; +## FAQs -async function testAttestKey() { - let aliasString = keyAliasString; - let aliasUint8 = StringToUint8Array(aliasString); - - let properties = new Array(); - properties[0] = { - tag: huks.HuksTag.HUKS_TAG_ALGORITHM, - value: huks.HuksKeyAlg.HUKS_ALG_RSA - }; - properties[1] = { - tag: huks.HuksTag.HUKS_TAG_KEY_STORAGE_FLAG, - value: huks.HuksKeyStorageType.HUKS_STORAGE_PERSISTENT - }; - properties[2] = { - tag: huks.HuksTag.HUKS_TAG_KEY_SIZE, - value: huks.HuksKeySize.HUKS_RSA_KEY_SIZE_2048 - }; - properties[3] = { - tag: huks.HuksTag.HUKS_TAG_PURPOSE, - value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_VERIFY - }; - properties[4] = { - tag: huks.HuksTag.HUKS_TAG_DIGEST, - value: huks.HuksKeyDigest.HUKS_DIGEST_SHA256 - }; - properties[5] = { - tag: huks.HuksTag.HUKS_TAG_PADDING, - value: huks.HuksKeyPadding.HUKS_PADDING_PSS - }; - properties[6] = { - tag: huks.HuksTag.HUKS_TAG_KEY_GENERATE_TYPE, - value: huks.HuksKeyGenerateType.HUKS_KEY_GENERATE_TYPE_DEFAULT - }; - properties[7] = { - tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, - value: huks.HuksCipherMode.HUKS_MODE_ECB - }; - let options = { - properties: properties - }; - await publicGenKeyFunc(aliasString, options); - - /* Configure the certificate parameter set. */ - let attestProperties = new Array(); - attestProperties[0] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_SEC_LEVEL_INFO, - value: securityLevel - }; - attestProperties[1] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_CHALLENGE, - value: challenge - }; - attestProperties[2] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_VERSION_INFO, - value: versionInfo - }; - attestProperties[3] = { - tag: huks.HuksTag.HUKS_TAG_ATTESTATION_ID_ALIAS, - value: aliasUint8 - }; - let huksOptions = { - properties: attestProperties - }; +### Cannot find name 'huks'. - await publicAttestKey(aliasString, huksOptions); +**security.huks.d.ts** is not imported. To solve the problem, add **import huks from '@ohos.security.huks'**. - await publicDeleteKeyFunc(aliasString, options); -} - -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Button() { - Text('testAttestKey') - .fontSize(30) - .fontWeight(FontWeight.Bold) - }.type(ButtonType.Capsule) - .margin({ - top: 20 - }) - .backgroundColor('#0D9FFB') - .onClick(()=>{ - testAttestKey(); - }) - } - .width('100%') - .height('100%') - } -} -``` +### Property 'finishSession' does not exist on type 'typeof huks'. Did you mean 'finish'? + +**finishSession()** is supported from API version 9. Update the SDK version or use the latest **security.huks.d.ts** file. \ No newline at end of file diff --git a/en/application-dev/security/huks-overview.md b/en/application-dev/security/huks-overview.md index b9b0b7a8530e41b40d1ed8d8c1eacb5ab451a7ad..18a1a076bf7d33aa9f5178b9f9edded37cfc862b 100644 --- a/en/application-dev/security/huks-overview.md +++ b/en/application-dev/security/huks-overview.md @@ -2,26 +2,72 @@ ## Introduction -OpenHarmony Universal KeyStore (HUKS) provides KeyStore (KS) capabilities for applications, including key management and key cryptography operations. HUKS also provides APIs for applications to import or generate keys. +OpenHarmony Universal KeyStore (HUKS) provides lifecycle key management capabilities, including key generation, storage, use, and destruction, and provides attestation for the keys stored in the HUKS. +The HUKS provides secure, lifecycle management of keys based on system security capabilities for services. With the HUKS, services do not need to implement key management. + + +The HUKS provides the following functions: + +- [Key Generation](huks-guidelines.md#key-generation) +- [Key Import](huks-guidelines.md#key-import) +- [Common Key Operations](huks-guidelines.md#common-key-operations) +- [Key Access Control](huks-guidelines.md#key-access-control) +- [Key Attestation](huks-guidelines.md#key-attestation) +- [Supported Algorithm Types and Parameter Combinations](huks-appendix.md#supported-algorithm-types-and-parameter-combinations) +- [Key Material Formats](huks-appendix.md#key-material-formats) + ## Basic Concepts -- HUKS provides key management functions, including encryption and decryption, signing and signature verification, key agreement and derivation, and Hash-based Message Authentication Code (HMAC) calculation. -- HUKS supports the following algorithms: AES and RSA in encryption and decryption, RSA, ECC, DSA, and ED25519 in signing and signature verification, PBKDF2 in key derivation, and DH, ECDH, and X25519 in key agreement. -- HUKS uses the OpenSSL and Mbed TLS algorithm libraries. +Before using the HUKS for development, you are advised to understand the following basic concepts: + +- 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. + +- 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). + ## Working Principles -HUKS manages keys through the following APIs in an Init-Update-Finish model: -- **InitSession**: reads the key, creates a session ID, and returns the session ID to the caller. +The security design of the HUKS includes the following: +- Always keep keys in a secure environment. -- **UpdateSession**: updates data by segment based on the session ID obtained by **InitSession()**. + 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. -- **FinishSession**: processes all the data transferred to HUKS and then releases resources. + 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. -> **NOTICE**
-> **AbortSession()** must be called to terminate the use of the key when an error occurs in any of **InitSession()**, **UpdateSession()**, and **FinishSession()**. + Only authorized services can access keys. For security-sensitive services, user identity authentication can be enabled for key access. +- Provide 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. + + +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. + +**Figure 1** HUKS working mechanism + +![huks_architect](figures/huks_architect.png) ## Constraints -N/A + + - Alias-based access + + The key material stored in the HUKS can be accessed by alias only. The key alias must be unique for an application. Otherwise, the key with the same alias will be replaced. The length of the key alias cannot exceed 64 bytes. + + - Data segment size + + All data is transmitted to the HUKS through the IPC channel. Due to the limitation of the IPC buffer size, data greater than 100 KB must be sliced before transmission, and the data segment cannot exceed 100 KB. + + - Mandatory parameters + + The cipher algorithm, key size, and purpose must be specified when a key is generated or imported. Other parameters (such as the working mode, padding mode, and hash algorithm) are optional. When a key is used, all parameters related to the cipher algorithm must be specified. + + - Key material format + + When a key (key pair, public key, or private key) is imported or exported, the key material must be in the format required by the HUKS. For details, see [Key Material Formats](huks-appendix.md#key-material-format).