• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Encryption and Decryption by Segment with an RSA Asymmetric Key Pair (ArkTS)
2
3<!--Kit: Crypto Architecture Kit-->
4<!--Subsystem: Security-->
5<!--Owner: @zxz--3-->
6<!--Designer: @lanming-->
7<!--Tester: @PAFT-->
8<!--Adviser: @zengyawen-->
9
10For details about the algorithm specifications, see [RSA](crypto-asym-encrypt-decrypt-spec.md#rsa).
11
12**Encryption**
13
141. Call [cryptoFramework.createAsyKeyGenerator](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreateasykeygenerator) and [AsyKeyGenerator.generateKeyPair](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#generatekeypair-1) to generate a 1024-bit RSA asymmetric key pair (**KeyPair**) with two primes. The number of primes is not specified by default. The **KeyPair** object includes a public key (**PubKey**) and a private key (**PriKey**).
15
16   In addition to the example in this topic, [RSA](crypto-asym-key-generation-conversion-spec.md#rsa) and [Randomly Generating an Asymmetric Key Pair](crypto-generate-asym-key-pair-randomly.md) may help you better understand how to generate an RSA asymmetric key pair. Note that the input parameters in the reference documents may be different from those in the example below.
17
182. Call [cryptoFramework.createCipher](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatecipher) with the string parameter **'RSA1024|PKCS1'** to create a **Cipher** instance for encryption. The key type is **RSA1024**, and the padding mode is **PKCS1**.
19
203. Call [Cipher.init](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#init-1) to initialize the **Cipher** instance. In **Cipher.init**, set **opMode** to **CryptoMode.ENCRYPT_MODE** (encryption) and **key** to **KeyPair.PubKey** (the key used for encryption).
21
224. Call [Cipher.doFinal](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#dofinal-1) multiple times to pass in the plaintext and encrypt it by segment.
23
24   The output of **doFinal** may be **null**. To avoid exceptions, always check whether the result is **null** before accessing specific data.
25
26   In this example, the plaintext is split by 64 bytes and encrypted multiple times by a 1024-bit key. A 128-byte ciphertext is generated each time.
27   > **NOTE**
28   > Segment-based encryption and decryption of asymmetric keys means that when the plaintext is longer than the data length supported by a single encryption or decryption operation, the data to be encrypted or decrypted needs to be divided into segments of proper length. For details, see [Asymmetric Encryption and Decryption](crypto-encrypt-decrypt-by-segment.md#asymmetric-encryption-and-decryption).
29
30**Decryption**
31
321. If RSA is used, the **Cipher** instance cannot be initialized repeatedly. Call [cryptoFramework.createCipher](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatecipher) to create a new **Cipher** instance.
33
342. Call [Cipher.init](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#init-1) to initialize the **Cipher** instance. In **Cipher.init**, set **opMode** to **CryptoMode.DECRYPT_MODE** (decryption) and **key** to **KeyPair.PriKey** (the key used for decryption). If PKCS1 is used, set **params** to **null**.
35
363. Call [Cipher.doFinal](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#dofinal-1) multiple times to pass in the ciphertext and decrypt it by segment.
37
38- Example (using asynchronous APIs):
39
40  ```ts
41  import { cryptoFramework } from '@kit.CryptoArchitectureKit';
42  import { buffer } from '@kit.ArkTS';
43  // Encrypt the message by segment.
44  async function rsaEncryptBySegment(pubKey: cryptoFramework.PubKey, plainText: cryptoFramework.DataBlob) {
45    let cipher = cryptoFramework.createCipher('RSA1024|PKCS1');
46    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null);
47    let plainTextSplitLen = 64;
48    let cipherText = new Uint8Array();
49    for (let i = 0; i < plainText.data.length; i += plainTextSplitLen ) {
50      let updateMessage = plainText.data.subarray(i, i + plainTextSplitLen );
51      let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
52      // Split the plaintext by 64 bytes and cyclically call doFinal() to encrypt the plaintext using a 1024-bit key. A 128-byte ciphertext is generated each time.
53      let updateOutput = await cipher.doFinal(updateMessageBlob);
54      let mergeText = new Uint8Array(cipherText.length + updateOutput.data.length);
55      mergeText.set(cipherText);
56      mergeText.set(updateOutput.data, cipherText.length);
57      cipherText = mergeText;
58    }
59    let cipherBlob: cryptoFramework.DataBlob = { data: cipherText };
60    return cipherBlob;
61  }
62  // Decrypt the message by segment.
63  async function rsaDecryptBySegment(priKey: cryptoFramework.PriKey, cipherText: cryptoFramework.DataBlob) {
64    let decoder = cryptoFramework.createCipher('RSA1024|PKCS1');
65    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, priKey, null);
66    let cipherTextSplitLen = 128; // Length of the ciphertext = Number of key bits/8
67    let decryptText = new Uint8Array();
68    for (let i = 0; i < cipherText.data.length; i += cipherTextSplitLen) {
69      let updateMessage = cipherText.data.subarray(i, i + cipherTextSplitLen);
70      let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
71      // Split the ciphertext by 128 bytes, decrypt the ciphertext, and combine the plaintext obtained each time.
72      let updateOutput = await decoder.doFinal(updateMessageBlob);
73      let mergeText = new Uint8Array(decryptText.length + updateOutput.data.length);
74      mergeText.set(decryptText);
75      mergeText.set(updateOutput.data, decryptText.length);
76      decryptText = mergeText;
77    }
78    let decryptBlob: cryptoFramework.DataBlob = { data: decryptText };
79    return decryptBlob;
80  }
81  async function rsaEncryptLongMessage() {
82    let message = "This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
83      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
84      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
85      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
86      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
87      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
88      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
89      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!";
90    let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024");  // Create an AsyKeyGenerator object.
91    let keyPair = await asyKeyGenerator.generateKeyPair(); // Randomly generate an RSA key pair.
92    let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
93    let encryptText = await rsaEncryptBySegment(keyPair.pubKey, plainText);
94    let decryptText = await rsaDecryptBySegment(keyPair.priKey, encryptText);
95    if (plainText.data.toString() === decryptText.data.toString()) {
96      console.info('decrypt ok');
97      console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8'));
98    } else {
99      console.error('decrypt failed');
100    }
101  }
102  ```
103
104- Example (using synchronous APIs):
105
106  ```ts
107  import { cryptoFramework } from '@kit.CryptoArchitectureKit';
108  import { buffer } from '@kit.ArkTS';
109  // Encrypt the message by segment.
110  function rsaEncryptBySegment(pubKey: cryptoFramework.PubKey, plainText: cryptoFramework.DataBlob) {
111    let cipher = cryptoFramework.createCipher('RSA1024|PKCS1');
112    cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, pubKey, null);
113    let plainTextSplitLen = 64;
114    let cipherText = new Uint8Array();
115    for (let i = 0; i < plainText.data.length; i += plainTextSplitLen ) {
116      let updateMessage = plainText.data.subarray(i, i + plainTextSplitLen );
117      let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
118      // Split the plaintext by 64 bytes and cyclically call doFinal() to encrypt the plaintext using a 1024-bit key. A 128-byte ciphertext is generated each time.
119      let updateOutput = cipher.doFinalSync(updateMessageBlob);
120      let mergeText = new Uint8Array(cipherText.length + updateOutput.data.length);
121      mergeText.set(cipherText);
122      mergeText.set(updateOutput.data, cipherText.length);
123      cipherText = mergeText;
124    }
125    let cipherBlob: cryptoFramework.DataBlob = { data: cipherText };
126    return cipherBlob;
127  }
128  // Decrypt the message by segment.
129  function rsaDecryptBySegment(priKey: cryptoFramework.PriKey, cipherText: cryptoFramework.DataBlob) {
130    let decoder = cryptoFramework.createCipher('RSA1024|PKCS1');
131    decoder.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, priKey, null);
132    let cipherTextSplitLen = 128; // Length of the ciphertext = Number of key bits/8
133    let decryptText = new Uint8Array();
134    for (let i = 0; i < cipherText.data.length; i += cipherTextSplitLen) {
135      let updateMessage = cipherText.data.subarray(i, i + cipherTextSplitLen);
136      let updateMessageBlob: cryptoFramework.DataBlob = { data: updateMessage };
137      // Split the ciphertext by 128 bytes, decrypt the ciphertext, and combine the plaintext obtained each time.
138      let updateOutput = decoder.doFinalSync(updateMessageBlob);
139      let mergeText = new Uint8Array(decryptText.length + updateOutput.data.length);
140      mergeText.set(decryptText);
141      mergeText.set(updateOutput.data, decryptText.length);
142      decryptText = mergeText;
143    }
144    let decryptBlob: cryptoFramework.DataBlob = { data: decryptText };
145    return decryptBlob;
146  }
147  function main() {
148    let message = "This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
149      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
150      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
151      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
152      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
153      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
154      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!" +
155      "This is a long plainTest! This is a long plainTest! This is a long plainTest! This is a long plainTest!";
156    let asyKeyGenerator = cryptoFramework.createAsyKeyGenerator("RSA1024");  // Create an AsyKeyGenerator object.
157    let keyPair = asyKeyGenerator.generateKeyPairSync(); // Randomly generate an RSA key pair.
158    let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
159    let encryptText = rsaEncryptBySegment(keyPair.pubKey, plainText);
160    let decryptText = rsaDecryptBySegment(keyPair.priKey, encryptText);
161    if (plainText.data.toString() === decryptText.data.toString()) {
162      console.info('decrypt ok');
163      console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8'));
164    } else {
165      console.error('decrypt failed');
166    }
167  }
168  ```
169