> This development guide applies to API version 9, OpenHarmony SDK version 3.2.7 or later, and JS development.
> This guide applies to JS development using OpenHarmony API version 9 and SDK version 3.2.7 or later.
## Generating and Converting Keys
## Generating and Converting a Key
**When to Use**
**When to Use**
Typical key generation operations involve the following:
Typical key generation operations involve the following:
1. Randomly create a key instance. This instance can be used for subsequent encryption and decryption.
- Randomly create a key instance for subsequent encryption and decryption.
2. Convert external or stored binary data into a key instance. This instance can be used for subsequent encryption and decryption.
- Convert external or stored binary data into a key instance for subsequent encryption and decryption.
3. Obtain the binary data of a key for storage or transmission.
- Obtain the binary data of a key for storage or transmission.
> **NOTE**
> **NOTE**<br>The key instance can be a symmetric key instance (**SymKey**) or an asymmetric key pair instance (**KeyPair**). The **KeyPair** instance consists a public key (**PubKey**) and a private key (**PriKey**). For details about the relationship between keys, see [Crypto Framework](../reference/apis/js-apis-cryptoFramework.md).
>
> The key instance can be a symmetric key instance (**SymKey**) or an asymmetric key pair instance (**KeyPair**). The **KeyPair** instance consists a public key (PubKey) and a private key (**PriKey**). For details about the relationship between keys, see [Crypto Framework](../reference/apis/js-apis-cryptoFramework.md).
**Available APIs**
**Available APIs**
...
@@ -32,10 +29,10 @@ The table below describes the APIs used in this guide.
...
@@ -32,10 +29,10 @@ The table below describes the APIs used in this guide.
|AsyKeyGenerator|generateKeyPair() : Promise\<KeyPair>|Generates an asymmetric key pair randomly. This API uses a promise to return the result.|
|AsyKeyGenerator|generateKeyPair() : Promise\<KeyPair>|Generates an asymmetric key pair randomly. This API uses a promise to return the result.|
|SymKeyGenerator|generateSymKey(callback : AsyncCallback\<SymKey>) : void|Generates a symmetric key randomly. This API uses an asynchronous callback to return the result.|
|SymKeyGenerator|generateSymKey(callback : AsyncCallback\<SymKey>) : void|Generates a symmetric key randomly. This API uses an asynchronous callback to return the result.|
|SymKeyGenerator|generateSymKey() : Promise\<SymKey>|Generates a symmetric key randomly. This API uses a promise to return the result.|
|SymKeyGenerator|generateSymKey() : Promise\<SymKey>|Generates a symmetric key randomly. This API uses a promise to return the result.|
| AsyKeyGenerator | convertKey(pubKey : DataBlob, priKey : DataBlob, callback : AsyncCallback\<KeyPair>) : void | Converts the binary data into a key pair. This API uses an asynchronous callback to return the result.<br>(**pubKey** or **priKey** can be **null**. That is, you can pass in only **pubKey** or **priKey**. As a result, the return **KeyPair** instance contains only the public or private key.) |
| AsyKeyGenerator | convertKey(pubKey : DataBlob, priKey : DataBlob, callback : AsyncCallback\<KeyPair>) : void | Converts binary data into a key pair. This API uses an asynchronous callback to return the result.<br>(**pubKey** or **priKey** can be **null**. That is, you can pass in only **pubKey** or **priKey**. As a result, the returned **KeyPair** instance contains only the public or private key.)|
| AsyKeyGenerator | convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise\<KeyPair> | Converts the binary data into a key pair. This API uses a promise to return the result.<br>(**pubKey** or **priKey** can be **null**. That is, you can pass in only **pubKey** or **priKey**. As a result, the returned **KeyPair** instance contains only the public or private key.) |
| AsyKeyGenerator | convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise\<KeyPair> | Converts binary data into a key pair. This API uses a promise to return the result.<br>(**pubKey** or **priKey** can be **null**. That is, you can pass in only **pubKey** or **priKey**. As a result, the returned **KeyPair** instance contains only the public or private key.)|
| SymKeyGenerator | convertKey(key : DataBlob, callback : AsyncCallback\<SymKey>) : void| Converts the binary data into a symmetric key. This API uses an asynchronous callback to return the result. |
| SymKeyGenerator | convertKey(key : DataBlob, callback : AsyncCallback\<SymKey>) : void| Converts binary data into a symmetric key. This API uses an asynchronous callback to return the result.|
| SymKeyGenerator |convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise\<KeyPair>| Converts the binary data into a symmetric key. This API uses a promise to return the result. |
| SymKeyGenerator |convertKey(pubKey : DataBlob, priKey : DataBlob) : Promise\<KeyPair>| Converts binary data into a symmetric key. This API uses a promise to return the result.|
| Key | getEncoded() : DataBlob; | Obtains the binary data of a key. (The child class instances of **Key** include **SymKey**, **PubKey**, and **PriKey**.)|
| Key | getEncoded() : DataBlob; | Obtains the binary data of a key. (The child class instances of **Key** include **SymKey**, **PubKey**, and **PriKey**.)|
**How to Develop**
**How to Develop**
...
@@ -46,7 +43,7 @@ Example 1: Randomly generate an asymmetric key pair and obtain its binary data.
...
@@ -46,7 +43,7 @@ Example 1: Randomly generate an asymmetric key pair and obtain its binary data.
2. Randomly generate an asymmetric key pair using **AsyKeyGenerator**.
2. Randomly generate an asymmetric key pair using **AsyKeyGenerator**.
3. Obtain binary data of the key pair generated.
3. Obtain binary data of the key pair generated.
For example, randomly generate an RSA key (1024 bits and two primes) using promise-based APIs.
The following sample code presents how to randomly generate an RSA key (1024 bits and two primes) using promise-based APIs:
@@ -103,7 +100,7 @@ function testGenerateAesKey() {
...
@@ -103,7 +100,7 @@ function testGenerateAesKey() {
Example 3: Generate an asymmetric key pair from the binary RSA key data.
Example 3: Generate an asymmetric key pair from the binary RSA key data.
1. Obtain the binary data of the RSA public or private key. The public key must comply with the ASN.1 syntax, X.509 specifications, and DER encoding format. The private key must comply with the ASN.1 syntax, PKCS #8 specifications, and DER encoding format.
1. Obtain the binary data of the RSA public or private key. The public key must comply with the ASN.1 syntax, X.509 specifications, and DER encoding format. The private key must comply with the ASN.1 syntax, PKCS #8 specifications, and DER encoding format.
2. Create an **AsyKeyGenerator** instance and call **convertKey()** to convert the key binary data (data of the private or public key, or both) passed in to a **KeyPair** instance.
2. Create an **AsyKeyGenerator** instance and call **convertKey()** to convert the key binary data (data of the private or public key, or both) into a **KeyPair** instance.
> The public key returned by **convertKey()** must be in the DER format complying with X.509 specifications, and the private key must be in the DER format complying with PKCS #8 specifications.
> The public key material to be converted in **convertKey()** must be in the DER format complying with X.509 specifications, and the private key material must be in the DER format complying with PKCS #8 specifications.
Example 4: Generate an asymmetric key pair from the binary ECC key data.
Example 4: Generate an asymmetric key pair from the binary ECC key data.
1. Obtain the ECC binary key data and encapsulate it into a **DataBlob** instance.
1. Obtain the ECC binary key data and encapsulate it into a **DataBlob** instance.
2. Call **convertKey()** to convert the key binary data (data of the private or public key, or both) passed in to a **KeyPair** instance.
2. Call **convertKey()** to convert the key binary data (data of the private or public key, or both) into to a **KeyPair** instance.
@@ -201,12 +200,12 @@ function testConvertAesKey() {
...
@@ -201,12 +200,12 @@ function testConvertAesKey() {
**When to Use**
**When to Use**
Important data needs to be encrypted in data storage or transmission for security purposes. Typical encryption and decryption operations involve the following:
Important data needs to be encrypted in data storage or transmission for security purposes. Typical encryption and decryption operations involve the following:
1. Encrypt and decrypt data using a symmetric key.
- Encrypt and decrypt data using a symmetric key.
2. Encrypt and decrypt data using an asymmetric key pair.
- Encrypt and decrypt data using an asymmetric key pair.
**Available APIs**
**Available APIs**
For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cryptoFramework.md).
For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cryptoFramework.md).<br>Due to the complexity of cryptographic algorithms, the implementation varies depending on the specifications and parameters you use, and cannot be enumerated by sample code. Before you start, understand the APIs in the API reference to ensure correct use of these APIs.
The table below describes the APIs used in this guide.
The table below describes the APIs used in this guide.
...
@@ -229,7 +228,7 @@ Example 1: Encrypt and decrypt data using a symmetric key.
...
@@ -229,7 +228,7 @@ Example 1: Encrypt and decrypt data using a symmetric key.
3. Create a **Cipher** instance.
3. Create a **Cipher** instance.
4. Encrypt or decrypt data.
4. Encrypt or decrypt data.
For example, use AES GCM to encrypt and decrypt data using promise-based APIs.
The following sample code presents how to use the AES-GCM to encrypt and decrypt data with promise-based APIs:
// Obtain the authentication information after encryption.
// In GCM mode, the encrypted authentication information needs to be obtained from the output of doFinal() and passed in globalGcmParams of init() in decryption.
if(finalOutput==null){// Check whether the result is null before using finalOutput.data.
console.info('GCM finalOutput is null');
console.info('GCM finalOutput is null');
}
}
}).catch(error=>{
}).catch(error=>{
...
@@ -364,7 +364,7 @@ function testAesGcm() {
...
@@ -364,7 +364,7 @@ function testAesGcm() {
}
}
```
```
For example, 3DES ECB is used. Generate a key from the existing data to encrypt and decrypt data using callback-based APIs.
The following sample code presents how to use the the 3DES ECB to convert existing data into a key and encrypt and decrypt data using callback-based APIs:
// Convert byte streams into strings in plaintext.
functionuint8ArrayToString(array){
letarrayString='';
for(leti=0;i<array.length;i++){
arrayString+=String.fromCharCode(array[i]);
}
returnarrayString;
}
// The algorithm library does not limit the number of update() times and the amount of data to be encrypted and decrypted each time. You can use update() multiple times based on the memory usage.
letupdateOutput=awaitglobalCipher.update(messageBlob);// Update by segment.
// Combine the result of each update() to obtain the ciphertext. In certain cases, the doFinal() results need to be combined, which depends on the cipher block mode
// and padding mode you use. In this example, the doFinal() result in GCM mode contains authTag but not ciphertext. Therefore, there is no need to combine the results.
// Convert byte streams into strings in plaintext.
functionuint8ArrayToString(array){
letarrayString='';
for(leti=0;i<array.length;i++){
arrayString+=String.fromCharCode(array[i]);
}
returnarrayString;
}
functionencryptLongMessagePromise(){
letglobalPlainText="This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!"+
"This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!";
letglobalCipherOutput;
letglobalDecodeOutput;
varglobalKeyPair;
letplainTextSplitLen=64;// The length of the plaintext to be encrypted or decrypted each time by RSA depends on the number of key bits and padding mode. For details, see the Crypto Framework Overview.
letcipherTextSplitLen=128;// Length of the ciphertext = Number of key bits/8
letkeyGenName="RSA1024";
letcipherAlgName="RSA1024|PKCS1";
letasyKeyGenerator=cryptoFramework.createAsyKeyGenerator(keyGenName);// Create an AsyKeyGenerator object.
letcipher=cryptoFramework.createCipher(cipherAlgName);// Create a Cipher object.
letdecoder=cryptoFramework.createCipher(cipherAlgName);// Create a Decoder object.
returnnewPromise((resolve,reject)=>{
setTimeout(()=>{
resolve("testRsaMultiDoFinal");
},10);
}).then(()=>{
returnasyKeyGenerator.generateKeyPair();// Generate an RSA key.
}).then(keyPair=>{
globalKeyPair=keyPair;// Save the key to global variables.
// Split the plaintext by 64 characters and cyclically call doFinal() to encrypt the plaintext. If a 1024-bit key is used, 128-byte ciphertext is generated each time.
> - In RSA encryption and decryption, **init()** cannot be repeatedly called to initialize the **Cipher** instance. You must create a **Cipher** instance for each of encryption and decryption.
> - In RSA encryption and decryption, **init()** cannot be repeatedly called to initialize the **Cipher** instance. You must create a **Cipher** instance for each encryption and decryption.
> - The RSA encryption has a limit on the length of the plaintext to be encrypted. For details, see "Basic Concepts" in [Crypto Framework Overview](cryptoFramework-overview.md).
> - The RSA encryption has a limit on the length of the plaintext to be encrypted. For details, see "Basic Concepts" in [Cryptographic Framework Overview](cryptoFramework-overview.md).
> - In RSA decryption, the length of the ciphertext to be decrypted each time is the number of bits of the RSA key divided by 8.
> - In RSA decryption, the length of the ciphertext to be decrypted each time is the number of bits of the RSA key divided by 8.
## Signing Data and Verifying Signatures
## Generating and Verifying a Signature
**When to Use**
**When to Use**
A digital signature can be used to verify the authenticity of a message. Typical signing and signature verification operations involve the following:
A digital signature can be used to verify the authenticity of a message. Typical signing and signature verification operations involve the following:
- Use RSA to sign data and verify the signature.
- Use the RSA to generate and verify a signature.
- Use ECC to sign data and verify the signature.
- Use the ECC to generate and verify a signature.
**Available APIs**
**Available APIs**
For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cryptoFramework.md).
For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cryptoFramework.md).<br>Due to the complexity of cryptographic algorithms, the implementation varies depending on the specifications and parameters you use, and cannot be enumerated by sample code. Before you start, understand the APIs in the API reference to ensure correct use of these APIs.
|Instance|API|Description|
|Instance|API|Description|
|---|---|---|
|---|---|---|
...
@@ -577,12 +859,12 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
...
@@ -577,12 +859,12 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
**How to Develop**
**How to Develop**
Example 1: Use RSA to sign data and verify the signature.
Example 1: Use the RSA to generate and verify a signature.
1. Generate an RSA key pair.<br>Call **createAsyKeyGenerator()** to create an **AsyKeyGenerator** instance and generate an RSA asymmetric key pair.
1. Generate an RSA key pair.<br>Call **createAsyKeyGenerator()** to create an **AsyKeyGenerator** instance and generate an RSA asymmetric key pair.
2. Create a **Sign** instance.<br>Call **createSign()** to create a **Sign** instance, initialize the **Sign** instance, and set a private key for signing.
2. Create a **Sign** instance.<br>Call **createSign()** to create a **Sign** instance, initialize the **Sign** instance, and set a private key for signing.
3. Generate a signature.<br>Call **update()** provided by the **Sign** class to add the data for signing and call **sign()** to generate a signature.
3. Generate a signature.<br>Call **update()** provided by the **Sign** class to add the data for signing and call **sign()** to generate a signature.
4. Create a **Verify** instance.<br>Call **createVerify()** to create a **Verify** instance, initialize the instance, and set a public key for signature verification.
4. Create a **Verify** instance.<br>Call **createVerify()** to create a **Verify** instance, initialize the instance, and set a public key for signature verification.
5. Verify the signature.<br>Call **update()** provided by the **Verify** class to add signature data and call **verify()** to verify the signature.
5. Verify the signature.<br>Call **update()** provided by the **Verify** class to add signature data and call **verify()** to verify the signature.
@@ -661,12 +943,12 @@ function verifyMessageCallback() {
...
@@ -661,12 +943,12 @@ function verifyMessageCallback() {
}
}
```
```
Example 2: Using ECC to sign data and verify the signature.
Example 2: Use the ECDSA to generate and verify a signature.
1. Generate an ECC key.<br>Call **createAsyKeyGenerator()** to create an **AsyKeyGenerator** instance and generate an ECC asymmetric key pair.
1. Generate an ECC key.<br>Call **createAsyKeyGenerator()** to create an **AsyKeyGenerator** instance and generate an ECC asymmetric key pair.
2. Create a **Sign** instance.<br>Call **createSign()** to create a **Sign** instance, initialize the **Sign** instance, and set a private key for signing.
2. Create a **Sign** instance.<br>Call **createSign()** to create a **Sign** instance, initialize the **Sign** instance, and set a private key for signing.
3. Generate a signature.<br>Call **update()** provided by the **Sign** class to add the data for signing and call **doFinal()** to generate a signature.
3. Generate a signature.<br>Call **update()** provided by the **Sign** class to add the data for signing and call **doFinal()** to generate a signature.
4. Create a **Verify** instance.<br>Call **createVerify()** to create a **Verify** instance, initialize the instance, and set a public key for signature verification.
4. Create a **Verify** instance.<br>Call **createVerify()** to create a **Verify** instance, initialize the instance, and set a public key for signature verification.
5. Verify the signature.<br>Call **update()** provided by the **Verify** class to add signature data and call **doFinal()** to verify the signature.
5. Verify the signature.<br>Call **update()** provided by the **Verify** class to add signature data and call **doFinal()** to verify the signature.
A message digest is a fixed size numeric representation of the content of a message, computed by a has function. The message digest is sent with the message. The receiver can generate a digest for the message and compare it with the digest received. If the two digests are the same, the message integrity is verified.
A message digest (MD) is a fixed size numeric representation of the content of a message, computed by a has function. It is sent with the message. The receiver can generate a digest for the message and compare it with the digest received. If the two digests are the same, the message integrity is verified.
Typical message digest operations involve the following:
Typical MD operations involve the following:
1. Create an **Md** instance.
1. Create an **Md** instance.
2. Add one or more segments of data for generating a digest.
2. Add one or more segments of data for generating a digest.
3. Compute a digest.
3. Compute a digest.
4. Obtain the algorithm and length of a digest.
4. Obtain the algorithm and length of a digest.
**Available APIs**
**Available APIs**
...
@@ -776,7 +1125,7 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
...
@@ -776,7 +1125,7 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
**How to Develop**
**How to Develop**
1. Call **createMd()** to create an **Md** instance.
1. Call **createMd()** to create an **Md** instance.
2. Call **update()** to update the data for computing a digest. **update()** can be called multiple times to update the data by segment.
2. Call **update()** to pass in the data for computing a digest. **update()** can be called multiple times to pass in the data by segment.
3. Call **digest()** to compute a digest.
3. Call **digest()** to compute a digest.
4. Obtain the digest algorithm and length of the digest generated.
4. Obtain the digest algorithm and length of the digest generated.
...
@@ -805,7 +1154,7 @@ function GenDataBlob(dataBlobLen) {
...
@@ -805,7 +1154,7 @@ function GenDataBlob(dataBlobLen) {
returndataBlob;
returndataBlob;
}
}
// Compute a message digest using promise-based APIs.
// Compute an MD using promise-based APIs.
functiondoMdByPromise(algName){
functiondoMdByPromise(algName){
varmd;
varmd;
try{
try{
...
@@ -814,8 +1163,13 @@ function doMdByPromise(algName) {
...
@@ -814,8 +1163,13 @@ function doMdByPromise(algName) {
console.error("[Promise]: error code: "+error.code+", message is: "+error.message);
console.error("[Promise]: error code: "+error.code+", message is: "+error.message);
}
}
console.error("[Promise]: Md algName is: "+md.algName);
console.error("[Promise]: Md algName is: "+md.algName);
// Initial update().
varpromiseMdUpdate=md.update(GenDataBlob(12));
varpromiseMdUpdate=md.update(GenDataBlob(12));
promiseMdUpdate.then(()=>{
promiseMdUpdate.then(()=>{
// Call update() multiple times based on service requirements.
promiseMdUpdate=md.update(GenDataBlob(12));
returnpromiseMdUpdate;
}).then(mdOutput=>{
varPromiseMdDigest=md.digest();
varPromiseMdDigest=md.digest();
returnPromiseMdDigest;
returnPromiseMdDigest;
}).then(mdOutput=>{
}).then(mdOutput=>{
...
@@ -827,7 +1181,7 @@ function doMdByPromise(algName) {
...
@@ -827,7 +1181,7 @@ function doMdByPromise(algName) {
});
});
}
}
// Compute a message digest using callback-based APIs.
// Compute an MD using callback-based APIs.
functiondoMdByCallback(algName){
functiondoMdByCallback(algName){
varmd;
varmd;
try{
try{
...
@@ -836,22 +1190,86 @@ function doMdByCallback(algName) {
...
@@ -836,22 +1190,86 @@ function doMdByCallback(algName) {
console.error("[Callback]: error code: "+error.code+", message is: "+error.message);
console.error("[Callback]: error code: "+error.code+", message is: "+error.message);
}
}
console.error("[Callback]: Md algName is: "+md.algName);
console.error("[Callback]: Md algName is: "+md.algName);
// Initial update().
md.update(GenDataBlob(12),(err,)=>{
md.update(GenDataBlob(12),(err,)=>{
if(err){
if(err){
console.error("[Callback]: err: "+err.code);
console.error("[Callback]: err: "+err.code);
}
}
md.digest((err1,mdOutput)=>{
// Call update() multiple times based on service requirements.
Changed **algoName** of the **ParamsSpec** structure to **algName**.
**Change Impact**
For the released JavaScript APIs that use **ParamsSpec** and its child classes **IvParamsSpec**, **GcmParamsSpec**, and **CcmParamsSpec** as parameters or return values, **algoName** must be changed to **algName**.
The change must be made for all the applications that use these APIs. Otherwise, the compilation in the SDK of the new version cannot be successful.
**Key API/Component Changes**
API prototype before the change:
```ts
interfaceParamsSpec{
/**
* Indicates the algorithm name. Should be set before initialization of a cipher object.
For details, see the APIs of **ParamsSpec** in [Crypto Framework](../../../application-dev/reference/apis/js-apis-cryptoFramework.md#paramsspec).
## Change of cl.security.2 ECC Algorithm Parameter Name from ECC512 to ECC521
**Change Impact**
Behavior of released JavaScript APIs will be changed.
The application needs to be adapted to obtain the correct result in the SDK of the new version.
**Key API/Component Changes**
The parameter passed in the APIs is changed from **ECC512** to **ECC521**. The related APIs remain unchanged. For details, see [Key Generation Specifications](../../../application-dev/security/cryptoFramework-overview.md#key-generation-specifications). The following APIs are involved: