未验证 提交 cfc2507f 编写于 作者: O openharmony_ci 提交者: Gitee

!15093 [翻译完成】#I6DKDG

Merge pull request !15093 from Annie_wang/PR14320
......@@ -2,21 +2,18 @@
> **NOTE**
>
> 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**
Typical key generation operations involve the following:
1. Randomly create a key instance. This instance can be used 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.
3. Obtain the binary data of a key for storage or transmission.
> **NOTE**
>
> 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).
- Randomly create a key instance for subsequent encryption and decryption.
- Convert external or stored binary data into a key instance for subsequent encryption and decryption.
- Obtain the binary data of a key for storage or transmission.
> **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).
**Available APIs**
......@@ -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.|
|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.|
| 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) : 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.) |
| 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(pubKey : DataBlob, priKey : DataBlob) : Promise\<KeyPair>| Converts the binary data into a symmetric key. This API uses a promise to return the result. |
| 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 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 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 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**.)|
**How to Develop**
......@@ -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**.
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:
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -75,7 +72,7 @@ Example 2: Randomly generate a symmetric key and obtain its binary data.
2. Randomly generate a symmetric key using **SymKeyGenerator**.
3. Obtain binary data of the key generated.
For example, randomly generate an AES key (256 bits) using promise-based APIs.
The following sample code presents how to randomly generate a 256-bit AES key using promise-based APIs:
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -103,7 +100,7 @@ function testGenerateAesKey() {
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.
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.
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -123,17 +120,19 @@ function convertAsyKey() {
> **NOTE**
>
> 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.
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.
```javascript
function convertEccAsyKey() {
let pubKeyArray = new Uint8Array([4,196,55,233,100,227,224,38,38,5,128,81,53,112,129,7,59,189,116,105,182,87,190,85,31,248,172,116,213,7,206,85,190,65,169,193,138,173,232,187,74,54,78,251,29,131,192,223,251,227,170,138,80,7,98,193,216,168,235,114,255,188,70,134,104]);
let priKeyArray = new Uint8Array([255,70,89,220,189,19,41,157,175,173,83,60,74,216,195,96,24,181,231,23,112,247,150,126,15,155,24,79,33,97,31,225]);
let pubKeyArray = new Uint8Array([48,89,48,19,6,7,42,134,72,206,61,2,1,6,8,42,134,72,206,61,3,1,7,3,66,0,4,83,96,142,9,86,214,126,106,247,233,92,125,4,128,138,105,246,162,215,71,81,58,202,121,26,105,211,55,130,45,236,143,55,16,248,75,167,160,167,106,2,152,243,44,68,66,0,167,99,92,235,215,159,239,28,106,124,171,34,145,124,174,57,92]);
let priKeyArray = new Uint8Array([48,49,2,1,1,4,32,115,56,137,35,207,0,60,191,90,61,136,105,210,16,27,4,171,57,10,61,123,40,189,28,34,207,236,22,45,223,10,189,160,10,6,8,42,134,72,206,61,3,1,7]);
let pubKeyBlob = { data: pubKeyArray };
let priKeyBlob = { data: priKeyArray };
let generator = cryptoFrameWork.createAsyKeyGenerator("ECC256");
......@@ -146,13 +145,13 @@ function convertEccAsyKey() {
}
```
Example 5: Generate a symmetric key from binary key data.
Example 5: Generate a symmetric key from binary data.
1. Create a **SymKeyGenerator** instance.
2. Generate a symmetric key from the binary data passed in.
3. Obtain binary data of the key generated.
For example, generate a 3DES key (192 bits only) using callback-based APIs.
The following sample code presents how to generate a 3DES key (192 bits only) using callback-based APIs:
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -201,12 +200,12 @@ function testConvertAesKey() {
**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:
1. Encrypt and decrypt data using a symmetric key.
2. Encrypt and decrypt data using an asymmetric key pair.
- Encrypt and decrypt data using a symmetric key.
- Encrypt and decrypt data using an asymmetric key pair.
**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.
......@@ -229,7 +228,7 @@ Example 1: Encrypt and decrypt data using a symmetric key.
3. Create a **Cipher** instance.
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:
```js
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -250,8 +249,9 @@ function genGcmParamsSpec() {
arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0]; // 16 bytes
let dataTag = new Uint8Array(arr);
let tagBlob = {data : dataTag};
let gcmParamsSpec = {iv : ivBlob, aad : aadBlob, authTag : tagBlob, algoName : "GcmParamsSpec"};
let tagBlob = {data : dataTag}; // The authTag of GCM is obtained by doFinal() in encryption and passed in params of init() in decryption.
let gcmParamsSpec = {iv : ivBlob, aad : aadBlob, authTag : tagBlob, algName : "GcmParamsSpec"};
return gcmParamsSpec;
}
......@@ -298,8 +298,8 @@ function testAesGcm() {
}, 10)
}).then(() => {
// Create a SymKeyGenerator instance.
let symAlgoName = 'AES128';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgoName);
let symAlgName = 'AES128';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
if (symKeyGenerator == null) {
console.error('createSymKeyGenerator failed');
return;
......@@ -311,9 +311,9 @@ function testAesGcm() {
globalGcmParams = genGcmParamsSpec();
// Create a Cipher instance.
let cipherAlgoName = 'AES128|GCM|PKCS7';
let cipherAlgName = 'AES128|GCM|PKCS7';
try {
globalCipher = cryptoFramework.createCipher(cipherAlgoName);
globalCipher = cryptoFramework.createCipher(cipherAlgName);
console.info(`cipher algName: ${globalCipher.algName}`);
} catch (error) {
console.error(`createCipher failed, ${error.code}, ${error.message}`);
......@@ -339,7 +339,7 @@ function testAesGcm() {
let promiseFinal = globalCipher.doFinal(null); // doFinal
return promiseFinal;
}).then(authTag => {
// 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.
globalGcmParams.authTag = authTag;
return;
}).then(() => {
......@@ -355,7 +355,7 @@ function testAesGcm() {
let promiseFinal = globalCipher.doFinal(null); // doFinal
return promiseFinal;
}).then(finalOutput => {
if (finalOutput == null) {
if (finalOutput == null) { // Check whether the result is null before using finalOutput.data.
console.info('GCM finalOutput is null');
}
}).catch(error => {
......@@ -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:
```js
import cryptoFramework from '@ohos.security.cryptoFramework';
......@@ -408,11 +408,11 @@ function genKeyMaterialBlob() {
return {data : keyMaterial};
}
// For example, 3DES ECB is used. Use existing data to generate a key to encrypt and decrypt data, and return the result in a callback.
// Use the 3DES ECB to Generate a key from the existing data and encrypt and decrypt data using callback-based APIs.
function test3DesEcb() {
// Create a SymKeyGenerator instance.
let symAlgoName = '3DES192';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgoName);
let symAlgName = '3DES192';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
if (symKeyGenerator == null) {
console.error('createSymKeyGenerator failed');
return;
......@@ -420,9 +420,9 @@ function test3DesEcb() {
console.info(`symKeyGenerator algName: ${symKeyGenerator.algName}`);
// Create a Cipher instance.
let cipherAlgoName = '3DES192|ECB|PKCS7';
let cipherAlgName = '3DES192|ECB|PKCS7';
try {
globalCipher = cryptoFramework.createCipher(cipherAlgoName);
globalCipher = cryptoFramework.createCipher(cipherAlgName);
console.info(`cipher algName: ${globalCipher.algName}`);
} catch (error) {
console.error(`createCipher failed, ${error.code}, ${error.message}`);
......@@ -473,7 +473,7 @@ function test3DesEcb() {
console.info('decrypt plainText: ' + uint8ArrayToString(updateOutput.data));
// doFinal
globalCipher.doFinal(null, (error, finalOutput) => {
if (finalOutput != null) {
if (finalOutput == null) { // Check whether the result is null before using finalOutput.data.
console.info("decrypt plainText:" + uint8ArrayToString(finalOutput.data));
}
})
......@@ -489,12 +489,153 @@ function test3DesEcb() {
}
}
```
The following sample code presents how to call **update()** multiple times to implement AES GCM encryption and decryption by using promise-based APIs:
```javascript
import cryptoFramework from '@ohos.security.cryptoFramework';
var globalCipher;
var globalGcmParams;
var globalKey;
var globalCipherText;
var globalPlainText;
function genGcmParamsSpec() {
let arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0]; // 12 bytes
let dataIv = new Uint8Array(arr);
let ivBlob = {data : dataIv};
arr = [0, 0, 0, 0 , 0, 0, 0, 0]; // 8 bytes
let dataAad = new Uint8Array(arr);
let aadBlob = {data : dataAad};
arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0]; // 16 bytes
let dataTag = new Uint8Array(arr);
let tagBlob = {data : dataTag};
let gcmParamsSpec = {iv : ivBlob, aad : aadBlob, authTag : tagBlob, algName : "GcmParamsSpec"};
return gcmParamsSpec;
}
// Output the byte streams in hexadecimal format.
function uint8ArrayToShowStr(uint8Array) {
return Array.prototype.map
.call(uint8Array, (x) => ('00' + x.toString(16)).slice(-2))
.join('');
}
// Convert byte streams into strings in plaintext.
function uint8ArrayToString(array) {
let arrayString = '';
for (let i = 0; i < array.length; i++) {
arrayString += String.fromCharCode(array[i]);
}
return arrayString;
}
// 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.
function testAesMultiUpdate() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('testAesMultiUpdate');
}, 10)
}).then(() => {
// Create a SymKeyGenerator instance.
let symAlgName = 'AES128';
let symKeyGenerator = cryptoFramework.createSymKeyGenerator(symAlgName);
if (symKeyGenerator == null) {
console.error('createSymKeyGenerator failed');
return;
}
console.info(`symKeyGenerator algName: ${symKeyGenerator.algName}`);
// Use the key generator to randomly generate a 128-bit symmetric key.
let promiseSymKey = symKeyGenerator.generateSymKey();
// Constructor
globalGcmParams = genGcmParamsSpec();
// Create a Cipher instance.
let cipherAlgName = 'AES128|GCM|PKCS7';
try {
globalCipher = cryptoFramework.createCipher(cipherAlgName);
console.info(`cipher algName: ${globalCipher.algName}`);
} catch (error) {
console.error(`createCipher failed, ${error.code}, ${error.message}`);
return;
}
return promiseSymKey;
}).then(key => {
let encodedKey = key.getEncoded();
console.info('key hex:' + uint8ArrayToShowStr(encodedKey.data));
globalKey = key;
return key;
}).then(key => {
// Initialize the cipher environment and start encryption.
let mode = cryptoFramework.CryptoMode.ENCRYPT_MODE;
let promiseInit = globalCipher.init(mode, key, globalGcmParams); // init
return promiseInit;
}).then(async () => {
let plainText = "aaaaa.....bbbbb.....ccccc.....ddddd.....eee"; // Assume that the plaintext contains 43 bytes.
let messageArr = [];
let updateLength = 20; // Pass in 20 bytes by update() each time.
globalCipherText = [];
for (let i = 0; i <= plainText.length; i++) {
if ((i % updateLength == 0 || i == plainText.length) && messageArr.length != 0) {
let message = new Uint8Array(messageArr);
let messageBlob = { data : message };
let updateOutput = await globalCipher.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.
globalCipherText = globalCipherText.concat(Array.from(updateOutput.data));
messageArr = [];
}
if (i < plainText.length) {
messageArr.push(plainText.charCodeAt(i));
}
}
return;
}).then(() => {
let promiseFinal = globalCipher.doFinal(null); // doFinal
return promiseFinal;
}).then(authTag => {
// Obtain the authentication information after encryption.
globalGcmParams.authTag = authTag;
return;
}).then(() => {
// Initialize the cipher environment and start decryption.
let mode = cryptoFramework.CryptoMode.DECRYPT_MODE;
let promiseInit = globalCipher.init(mode, globalKey, globalGcmParams); // init
return promiseInit;
}).then(async () => {
let updateLength = 20;
let updateTimes = Math.ceil(globalCipherText.length / updateLength); // Round up to the nearest integer.
globalPlainText = "";
for (let i = 0; i < updateTimes; i++) {
let messageArr = globalCipherText.slice(i * updateLength, (i + 1) * updateLength);
let message = new Uint8Array(messageArr);
let messageBlob = { data : message };
let updateOutput = await globalCipher.update(messageBlob); // Pass in data by segment.
globalPlainText += uint8ArrayToString(updateOutput.data); // Restore the original plaintext.
}
return;
}).then(() => {
let promiseFinal = globalCipher.doFinal(null); // doFinal
return promiseFinal;
}).then(finalOutput => {
if (finalOutput == null) {
console.info('GCM finalOutput is null');
}
console.info(`decrypt output: ${globalPlainText}`);
}).catch(error => {
console.error(`catch error, ${error.code}, ${error.message}`);
})
}
```
Example 2: Encrypt and decrypt data using an 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 **Cipher** instance.<br> Call **createCipher()** to create a **Cipher** instance, and set the key and encryption/decryption mode.
3. Perform encryption and decryption operations.<br> Call **doFinal()** provided by the **Cipher** instance to encrypt data or decrypt data.
1. Generate an RSA key pair.<br>Call **createAsyKeyGenerator()** to create an **AsyKeyGenerator** instance and generate an RSA asymmetric key pair.
2. Create a **Cipher** instance.<br>Call **createCipher()** to create a **Cipher** instance, and set the key and encryption/decryption mode.
3. Perform encryption and decryption operations.<br>Call **doFinal()** provided by the **Cipher** instance to encrypt data or decrypt data.
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
......@@ -538,25 +679,166 @@ function encryptMessageCallback() {
})
})
}
function decryptMessageProMise() {
let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
let cipher = cryptoFramework.createCipher("RSA1024|PKCS1");
let decoder = cryptoFramework.createCipher("RSA1024|PKCS1");
let keyGenPromise = rsaGenerator.generateKeyPair();
let keyPair;
let cipherDataBlob;
let input = { data : stringToUint8Array(plan) };
keyGenPromise.then(rsaKeyPair => {
keyPair = rsaKeyPair;
return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null);
}).then(() => {
return cipher.doFinal(input);
}).then(dataBlob => {
console.info("EncryptOutPut is " + dataBlob.data);
AlertDialog.show({message : "output" + dataBlob.data});
cipherDataBlob = dataBlob;
return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null);
}).then(() => {
return decoder.doFinal(cipherDataBlob);
}).then(decodeData => {
if (decodeData.data.toString() === input.data.toString()) {
AlertDialog.show({message : "decrypt success"});
return;
}
AlertDialog.show({message : "decrypt fail"});
});
}
function decryptMessageCallback() {
let rsaGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024|PRIMES_2");
let cipher = cryptoFramework.createCipher("RSA1024|PKCS1");
let decoder = cryptoFramework.createCipher("RSA1024|PKCS1");
let plainText = "this is cipher text";
let input = {data : stringToUint8Array(plainText) };
let cipherData;
let keyPair;
rsaGenerator.generateKeyPair(function (err, newKeyPair) {
keyPair = newKeyPair;
cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, keyPair.pubKey, null, function (err, data) {
cipher.doFinal(input, function (err, data) {
AlertDialog.show({ message : "EncryptOutPut is " + data.data} );
cipherData = data;
decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, keyPair.priKey, null, function (err, data) {
decoder.doFinal(cipherData, function (err, data) {
if (input.data.toString() === data.data.toString()) {
AlertDialog.show({ message : "decrype success"} );
return;
}
AlertDialog.show({ message : "decrype fail"} );
});
});
});
});
});
}
```
The following sample code presents how to implement RSA asymmetric encryption and decryption (**doFinal()** is called multiple times):
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
}
// Convert byte streams into strings in plaintext.
function uint8ArrayToString(array) {
let arrayString = '';
for (let i = 0; i < array.length; i++) {
arrayString += String.fromCharCode(array[i]);
}
return arrayString;
}
function encryptLongMessagePromise() {
let globalPlainText = "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!";
let globalCipherOutput;
let globalDecodeOutput;
var globalKeyPair;
let plainTextSplitLen = 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.
let cipherTextSplitLen = 128; // Length of the ciphertext = Number of key bits/8
let keyGenName = "RSA1024";
let cipherAlgName = "RSA1024|PKCS1";
let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName); // Create an AsyKeyGenerator object.
let cipher = cryptoFramework.createCipher(cipherAlgName); // Create a Cipher object.
let decoder = cryptoFramework.createCipher(cipherAlgName); // Create a Decoder object.
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("testRsaMultiDoFinal");
}, 10);
}).then(() => {
return asyKeyGenerator.generateKeyPair(); // Generate an RSA key.
}).then(keyPair => {
globalKeyPair = keyPair; // Save the key to global variables.
return cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, globalKeyPair.pubKey, null);
}).then(async () => {
globalCipherOutput = [];
// 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.
for (let i = 0; i < (globalPlainText.length / plainTextSplitLen); i++) {
let tempStr = globalPlainText.substr(i * plainTextSplitLen, plainTextSplitLen);
let tempBlob = { data : stringToUint8Array(tempStr) };
let tempCipherOutput = await cipher.doFinal(tempBlob);
globalCipherOutput = globalCipherOutput.concat(Array.from(tempCipherOutput.data));
}
console.info(`globalCipherOutput len is ${globalCipherOutput.length}, data is: ${globalCipherOutput.toString()}`);
return;
}).then(() =>{
return decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, globalKeyPair.priKey, null);
}).then(async() => {
globalDecodeOutput = [];
// Split and decrypt the ciphertext by 128 bytes, and combine the plaintext obtained each time.
for (let i = 0; i < (globalCipherOutput.length / cipherTextSplitLen); i++) {
let tempBlobData = globalCipherOutput.slice(i * cipherTextSplitLen, (i + 1) * cipherTextSplitLen);
let message = new Uint8Array(tempBlobData);
let tempBlob = { data : message };
let tempDecodeOutput = await decoder.doFinal(tempBlob);
globalDecodeOutput += uint8ArrayToString(tempDecodeOutput.data);
}
if (globalDecodeOutput === globalPlainText) {
console.info(`encode and decode success`);
} else {
console.info(`encode and decode error`);
}
return;
}).catch(error => {
console.error(`catch error, ${error.code}, ${error.message}`);
})
}
```
> **NOTE**
>
> - 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.
> - 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).
> - 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 [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.
## Signing Data and Verifying Signatures
## Generating and Verifying a Signature
**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:
- Use RSA to sign data and verify the signature.
- Use ECC to sign data and verify the signature.
- Use the RSA to generate and verify a signature.
- Use the ECC to generate and verify a signature.
**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|
|---|---|---|
......@@ -577,12 +859,12 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
**How to Develop**
Example 1: Use RSA to sign data and verify the signature.
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.
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.
5. Verify the signature.<br> Call **update()** provided by the **Verify** class to add signature data and call **verify()** to 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.
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.
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.
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
......@@ -661,12 +943,12 @@ function verifyMessageCallback() {
}
```
Example 2: Using ECC to sign data and verify the signature.
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.
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.
5. Verify the signature.<br> Call **update()** provided by the **Verify** class to add signature data and call **doFinal()** to 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.
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.
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.
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
......@@ -745,18 +1027,85 @@ function verifyMessageCallback() {
})
}
```
The following sample code presents how to call **update()** multiple times to implement signing and signature verification:
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpArray = new Uint8Array(arr);
return tmpArray;
}
function signLongMessagePromise() {
let globalPlainText = "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!";
let globalSignData;
let textSplitLen = 64; // Customized data splitting length.
let keyGenName = "RSA1024";
let cipherAlgName = "RSA1024|PKCS1|SHA256";
let globalKeyPair;
let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator(keyGenName); // Create an AsyKeyGenerator object.
let signer = cryptoFramework.createSign(cipherAlgName); //Create a cipher object for encryption.
let verifier = cryptoFramework.createVerify(cipherAlgName); // Create a Decoder object for decryption.
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("testRsaMultiUpdate");
}, 10);
}).then(() => {
return asyKeyGenerator.generateKeyPair(); // Generate an RSA key.
}).then(keyPair => {
globalKeyPair = keyPair; // Save the key to global variables.
return signer.init(globalKeyPair.priKey);
}).then(async () => {
// If the plaintext is too large, split the plaintext based on the specified length and cyclically call update() to pass in the plaintext.
for (let i = 0; i < (globalPlainText.length / textSplitLen); i++) {
let tempStr = globalPlainText.substr(i * textSplitLen, textSplitLen);
let tempBlob = { data : stringToUint8Array(tempStr) };
await signer.update(tempBlob);
}
return signer.sign(null);
}).then(data =>{
globalSignData = data.data;
console.info(`globalSignOutput len is ${globalSignData.length}, data is: ${globalSignData.toString()}`);
return verifier.init(globalKeyPair.pubKey);
}).then(async() => {
// Split and decrypt the ciphertext by 128 bytes, and combine the plaintext obtained each time.
for (let i = 0; i < (globalPlainText.length / textSplitLen); i++) {
let tempData = globalPlainText.slice(i * textSplitLen, (i + 1) * textSplitLen);
let tempBlob = { data : stringToUint8Array(tempData) };
await verifier.update(tempBlob);
}
return verifier.verify(null, { data : globalSignData});
}).then(res => {
console.info(`verify res is ${res}`);
}).catch(error => {
console.error(`catch error, ${error.code}, ${error.message}`);
})
}
```
## Generating a Digest
**When to Use**
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.
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.
**Available APIs**
......@@ -776,7 +1125,7 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
**How to Develop**
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.
4. Obtain the digest algorithm and length of the digest generated.
......@@ -805,7 +1154,7 @@ function GenDataBlob(dataBlobLen) {
return dataBlob;
}
// Compute a message digest using promise-based APIs.
// Compute an MD using promise-based APIs.
function doMdByPromise(algName) {
var md;
try {
......@@ -814,8 +1163,13 @@ function doMdByPromise(algName) {
console.error("[Promise]: error code: " + error.code + ", message is: " + error.message);
}
console.error("[Promise]: Md algName is: " + md.algName);
// Initial update().
var promiseMdUpdate = md.update(GenDataBlob(12));
promiseMdUpdate.then(() => {
// Call update() multiple times based on service requirements.
promiseMdUpdate = md.update(GenDataBlob(12));
return promiseMdUpdate;
}).then(mdOutput => {
var PromiseMdDigest = md.digest();
return PromiseMdDigest;
}).then(mdOutput => {
......@@ -827,7 +1181,7 @@ function doMdByPromise(algName) {
});
}
// Compute a message digest using callback-based APIs.
// Compute an MD using callback-based APIs.
function doMdByCallback(algName) {
var md;
try {
......@@ -836,22 +1190,86 @@ function doMdByCallback(algName) {
console.error("[Callback]: error code: " + error.code + ", message is: " + error.message);
}
console.error("[Callback]: Md algName is: " + md.algName);
// Initial update().
md.update(GenDataBlob(12), (err,) => {
if (err) {
console.error("[Callback]: err: " + err.code);
}
md.digest((err1, mdOutput) => {
// Call update() multiple times based on service requirements.
md.update(GenDataBlob(12), (err1,) => {
if (err1) {
console.error("[Callback]: err: " + err1.code);
} else {
console.error("[Callback]: MD result: " + mdOutput.data);
var mdLen = md.getMdLength();
console.error("[Callback]: MD len: " + mdLen);
}
md.digest((err2, mdOutput) => {
if (err2) {
console.error("[Callback]: err: " + err2.code);
} else {
console.error("[Callback]: MD result: " + mdOutput.data);
var mdLen = md.getMdLength();
console.error("[Callback]: MD len: " + mdLen);
}
});
});
});
}
```
The following sample code presents how to call **update()** multiple times to update the MD:
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
async function updateData(index, obj, data) {
console.error("update " + (index + 1) + " MB data...");
return obj.update(data);
}
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpUint8Array = new Uint8Array(arr);
return tmpUint8Array;
}
function GenDataBlob(dataBlobLen) {
var dataBlob;
if (dataBlobLen == 12) {
dataBlob = {data: stringToUint8Array("my test data")};
} else {
console.error("GenDataBlob: dataBlobLen is invalid");
dataBlob = {data: stringToUint8Array("my test data")};
}
return dataBlob;
}
function LoopMdPromise(algName, loopSize) {
var md;
try {
md = cryptoFramework.createMd(algName);
} catch (error) {
console.error("[Promise]: error code: " + error.code + ", message is: " + error.message);
return;
}
console.error("[Promise]: Md algName is: " + md.algName);
var promiseMdUpdate = md.update(GenDataBlob(12));
promiseMdUpdate.then(() => {
var PromiseMdDigest = md.digest();
return PromiseMdDigest;
}).then(async () => {
for (var i = 0; i < loopSize; i++) {
await updateData(i, md, GenDataBlob(12));
}
var PromiseMdDigest = md.digest();
return PromiseMdDigest;
}).then(mdOutput => {
console.error("[Promise]: MD result: " + mdOutput.data);
var mdLen = md.getMdLength();
console.error("[Promise]: MD len: " + mdLen);
}).catch(error => {
console.error("[Promise]: error: " + error.message);
});
}
```
## Performing Key Agreement
......@@ -871,7 +1289,7 @@ For details about the APIs, see [Crypto Framework](../reference/apis/js-apis-cry
**How to Develop**
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. Generate a shared secret by using the private and public ECC keys.
```javascript
......@@ -970,7 +1388,6 @@ function GenDataBlob(dataBlobLen) {
return dataBlob;
}
// Generate a MAC using promise-based APIs.
function doHmacByPromise(algName) {
var mac;
try {
......@@ -988,6 +1405,11 @@ function doHmacByPromise(algName) {
var promiseMacInit = mac.init(symKey);
return promiseMacInit;
}).then(() => {
// Initial update().
var promiseMacUpdate = mac.update(GenDataBlob(12));
return promiseMacUpdate;
}).then(() => {
// Call update() multiple times based on service requirements.
var promiseMacUpdate = mac.update(GenDataBlob(12));
return promiseMacUpdate;
}).then(() => {
......@@ -1023,35 +1445,105 @@ function doHmacByCallback(algName) {
if (err1) {
console.error("[Callback]: err: " + err1.code);
}
// Initial update().
mac.update(GenDataBlob(12), (err2, ) => {
if (err2) {
console.error("[Callback]: err: " + err2.code);
}
mac.doFinal((err3, macOutput) => {
// Call update() multiple times based on service requirements.
mac.update(GenDataBlob(12), (err3, ) => {
if (err3) {
console.error("[Callback]: err: " + err3.code);
} else {
console.error("[Callback]: HMAC result: " + macOutput.data);
var macLen = mac.getMacLength();
console.error("[Callback]: MAC len: " + macLen);
}
mac.doFinal((err4, macOutput) => {
if (err4) {
console.error("[Callback]: err: " + err4.code);
} else {
console.error("[Callback]: HMAC result: " + macOutput.data);
var macLen = mac.getMacLength();
console.error("[Callback]: MAC len: " + macLen);
}
});
});
});
});
});
}
```
The following sample code presents how to call **update()** multiple times to update the MAC:
```javascript
import cryptoFramework from "@ohos.security.cryptoFramework"
async function updateData(index, obj, data) {
console.error("update " + (index + 1) + " MB data...");
return obj.update(data);
}
function stringToUint8Array(str) {
var arr = [];
for (var i = 0, j = str.length; i < j; ++i) {
arr.push(str.charCodeAt(i));
}
var tmpUint8Array = new Uint8Array(arr);
return tmpUint8Array;
}
function GenDataBlob(dataBlobLen) {
var dataBlob;
if (dataBlobLen == 12) {
dataBlob = {data: stringToUint8Array("my test data")};
} else {
console.error("GenDataBlob: dataBlobLen is invalid");
dataBlob = {data: stringToUint8Array("my test data")};
}
return dataBlob;
}
function LoopHmacPromise(algName, loopSize) {
var mac;
try {
mac = cryptoFramework.createMac(algName);
} catch (error) {
console.error("[Promise]: error code: " + error.code + ", message is: " + error.message);
return;
}
console.error("[Promise]: Mac algName is: " + mac.algName);
var KeyBlob = {
data : stringToUint8Array("12345678abcdefgh")
}
var symKeyGenerator = cryptoFramework.createSymKeyGenerator("AES128");
var promiseConvertKey = symKeyGenerator.convertKey(KeyBlob);
promiseConvertKey.then(symKey => {
var promiseMacInit = mac.init(symKey);
return promiseMacInit;
}).then(async () => {
for (var i = 0; i < loopSize; i++) {
await updateData(i, mac, GenDataBlob(12));
}
var promiseMacUpdate = mac.update(GenDataBlob(12));
return promiseMacUpdate;
}).then(() => {
var PromiseMacDoFinal = mac.doFinal();
return PromiseMacDoFinal;
}).then(macOutput => {
console.error("[Promise]: HMAC result: " + macOutput.data);
var macLen = mac.getMacLength();
console.error("[Promise]: MAC len: " + macLen);
}).catch(error => {
console.error("[Promise]: error: " + error.message);
});
}
```
## Generating Random Numbers
## Generating a Random Number
**When to Use**
Typical random number operations involve the following:
1. Generate a random number.
2. Set a seed based on the random number generated.
- Generate a random number.
- Set a seed based on the random number generated.
**Available APIs**
......
# Security Subsystem Changelog
## cl.security.1 ParamsSpec Attribute Name Change
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
interface ParamsSpec {
/**
* Indicates the algorithm name. Should be set before initialization of a cipher object.
* @type { string }
* @syscap SystemCapability.Security.CryptoFramework
* @since 9
*/
algoName : string;
}
```
API prototype after the change:
```ts
interface ParamsSpec {
/**
* Indicates the algorithm name. Should be set before initialization of a cipher object.
* @type { string }
* @syscap SystemCapability.Security.CryptoFramework
* @since 9
*/
algName : string;
}
```
**Adaptation Guide**
Change **algoName** to **algName** in **ParamsSpec** and its child classes **IvParamsSpec**, **GcmParamsSpec**, and **CcmParamsSpec**.
```ts
function genGcmParamsSpec() {
let arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0 , 0, 0]; // 12 bytes
let dataIv = new Uint8Array(arr);
let ivBlob = {data : dataIv};
arr = [0, 0, 0, 0 , 0, 0, 0, 0]; // 8 bytes
let dataAad = new Uint8Array(arr);
let aadBlob = {data : dataAad};
arr = [0, 0, 0, 0 , 0, 0, 0, 0, 0, 0, 0, 0 , 0, 0, 0, 0]; // 16 bytes
let dataTag = new Uint8Array(arr);
let tagBlob = {data : dataTag};
let gcmParamsSpec = {iv : ivBlob, aad : aadBlob, authTag : tagBlob, algName : "GcmParamsSpec"};
return gcmParamsSpec;
}
```
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:
cryptoFramework.createAsyKeyGenerator
cryptoFramework.createSign
cryptoFramework.createVerify
cryptoFramework.createKeyAgreement
**Adaptation Guide**
```js
import cryptoFramework from "@ohos.security.cryptoFramework"
let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator("ECC521");
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册