1# Encryption and Decryption with an AES Symmetric Key (GCM Mode) (ArkTS)
2
3
4For details about the algorithm specifications, see [AES](crypto-sym-encrypt-decrypt-spec.md#aes).
5
6
7**Encryption**
8
9
101. Use [cryptoFramework.createSymKeyGenerator](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatesymkeygenerator) and [SymKeyGenerator.generateSymKey](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#generatesymkey-1) to generate a 128-bit AES symmetric key (**SymKey**).
11
12   In addition to the example in this topic, [AES](crypto-sym-key-generation-conversion-spec.md#aes) and [Randomly Generating a Symmetric Key](crypto-generate-sym-key-randomly.md) may help you better understand how to generate an AES symmetric key. Note that the input parameters in the reference documents may be different from those in the example below.
13
142. Use [cryptoFramework.createCipher](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#cryptoframeworkcreatecipher) with the string parameter **'AES128|GCM|PKCS7'** to create a **Cipher** instance. The key type is **AES128**, block cipher mode is **GCM**, and the padding mode is **PKCS7**.
15
163. Use [Cipher.init](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#init-1) to initialize the **Cipher** instance. In the **Cipher.init** API, set **opMode** to **CryptoMode.ENCRYPT_MODE** (encryption), **key** to **SymKey** (the key for encryption), and **params** to **GcmParamsSpec** corresponding to the GCM mode.
17
184. Use [Cipher.update](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#update-1) to pass in the data to be encrypted (plaintext).
19
20   Currently, the amount of data to be passed in by a single **Cipher.update** is not limited. You can determine how to pass in data based on the data volume.
21
22   - If a small amount of data is to be encrypted, you can use **Cipher.doFinal** immediately after **Cipher.init**.
23   - If a large amount of data is to be encrypted, you can call **Cipher.update** multiple times to pass in the data by segment.
24
255. Use [Cipher.doFinal](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#dofinal-1) to obtain the encrypted data.
26   - If data has been passed in by **Cipher.update**, pass in **null** in the **data** parameter of **Cipher.doFinal**.
27   - The output of **Cipher.doFinal** may be **null**. To avoid exceptions, always check whether the result is **null** before accessing specific data.
28
296. Obtain [GcmParamsSpec](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#gcmparamsspec).authTag as the authentication information for decryption.
30   In GCM mode, extract the last 16 bytes from the encrypted data as the authentication information for initializing the **Cipher** instance in decryption. In the example, **authTag** is of 16 bytes.
31
32
33**Decryption**
34
35
361. Use [Cipher.init](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#init-1) to initialize the **Cipher** instance. In the **Cipher.init** API, set **opMode** to **CryptoMode.DECRYPT_MODE** (decryption), **key** to **SymKey** (the key for decryption), and **params** to **GcmParamsSpec** corresponding to the GCM mode.
37
382. Use [Cipher.update](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#update-1) to pass in the data to be decrypted (ciphertext).
39
403. Use [Cipher.doFinal](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#dofinal-1) to obtain the decrypted data.
41
42
43- Example (using asynchronous APIs):
44
45  ```ts
46  import { cryptoFramework } from '@kit.CryptoArchitectureKit';
47  import { buffer } from '@kit.ArkTS';
48
49  function generateRandom(len: number) {
50    let rand = cryptoFramework.createRandom();
51    let generateRandSync = rand.generateRandomSync(len);
52    return generateRandSync;
53  }
54
55  function genGcmParamsSpec() {
56    let ivBlob = generateRandom(12);
57    let arr = [1, 2, 3, 4, 5, 6, 7, 8]; // 8 bytes
58    let dataAad = new Uint8Array(arr);
59    let aadBlob: cryptoFramework.DataBlob = { data: dataAad };
60    arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes
61    let dataTag = new Uint8Array(arr);
62    let tagBlob: cryptoFramework.DataBlob = {
63      data: dataTag
64    };
65    // Obtain the GCM authTag from the Cipher.doFinal result in encryption and fill it in the params parameter of Cipher.init in decryption.
66    let gcmParamsSpec: cryptoFramework.GcmParamsSpec = {
67      iv: ivBlob,
68      aad: aadBlob,
69      authTag: tagBlob,
70      algName: "GcmParamsSpec"
71    };
72    return gcmParamsSpec;
73  }
74
75  let gcmParams = genGcmParamsSpec();
76
77  // Encrypt the message.
78  async function encryptMessagePromise(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
79    let cipher = cryptoFramework.createCipher('AES128|GCM|PKCS7');
80    await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, gcmParams);
81    let encryptUpdate = await cipher.update(plainText);
82    // In GCM mode, pass in null in Cipher.doFinal in encryption. Obtain the tag data and fill it in the gcmParams object.
83    gcmParams.authTag = await cipher.doFinal(null);
84    return encryptUpdate;
85  }
86  // Decrypt the message.
87  async function decryptMessagePromise(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
88    let decoder = cryptoFramework.createCipher('AES128|GCM|PKCS7');
89    await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, gcmParams);
90    let decryptUpdate = await decoder.update(cipherText);
91    // In GCM mode, pass in null in Cipher.doFinal in decryption. Verify the tag data passed in Cipher.init. If the verification fails, an exception will be thrown.
92    let decryptData = await decoder.doFinal(null);
93    if (decryptData == null) {
94      console.info('GCM decrypt success, decryptData is null');
95    }
96    return decryptUpdate;
97  }
98  async function genSymKeyByData(symKeyData: Uint8Array) {
99    let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
100    let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128');
101    let symKey = await aesGenerator.convertKey(symKeyBlob);
102    console.info('convertKey success');
103    return symKey;
104  }
105  async function main() {
106    let keyData = new Uint8Array([83, 217, 231, 76, 28, 113, 23, 219, 250, 71, 209, 210, 205, 97, 32, 159]);
107    let symKey = await genSymKeyByData(keyData);
108    let message = "This is a test";
109    let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
110    let encryptText = await encryptMessagePromise(symKey, plainText);
111    let decryptText = await decryptMessagePromise(symKey, encryptText);
112    if (plainText.data.toString() === decryptText.data.toString()) {
113      console.info('decrypt ok');
114      console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8'));
115    } else {
116      console.error('decrypt failed');
117    }
118  }
119  ```
120
121- Example (using synchronous APIs):
122
123  ```ts
124  import { cryptoFramework } from '@kit.CryptoArchitectureKit';
125  import { buffer } from '@kit.ArkTS';
126
127  function generateRandom(len: number) {
128    let rand = cryptoFramework.createRandom();
129    let generateRandSync = rand.generateRandomSync(len);
130    return generateRandSync;
131  }
132
133  function genGcmParamsSpec() {
134    let ivBlob = generateRandom(12);
135    let arr = [1, 2, 3, 4, 5, 6, 7, 8]; // 8 bytes
136    let dataAad = new Uint8Array(arr);
137    let aadBlob: cryptoFramework.DataBlob = { data: dataAad };
138    arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes
139    let dataTag = new Uint8Array(arr);
140    let tagBlob: cryptoFramework.DataBlob = {
141      data: dataTag
142    };
143    // Obtain the GCM authTag from the Cipher.doFinal result in encryption and fill it in the params parameter of Cipher.init in decryption.
144    let gcmParamsSpec: cryptoFramework.GcmParamsSpec = {
145      iv: ivBlob,
146      aad: aadBlob,
147      authTag: tagBlob,
148      algName: "GcmParamsSpec"
149    };
150    return gcmParamsSpec;
151  }
152
153  let gcmParams = genGcmParamsSpec();
154
155  // Encrypt the message.
156  function encryptMessage(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) {
157    let cipher = cryptoFramework.createCipher('AES128|GCM|PKCS7');
158    cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, gcmParams);
159    let encryptUpdate = cipher.updateSync(plainText);
160    // In GCM mode, pass in null in Cipher.doFinal in encryption. Obtain the tag data and fill it in the gcmParams object.
161    gcmParams.authTag = cipher.doFinalSync(null);
162    return encryptUpdate;
163  }
164  // Decrypt the message.
165  function decryptMessage(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) {
166    let decoder = cryptoFramework.createCipher('AES128|GCM|PKCS7');
167    decoder.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, gcmParams);
168    let decryptUpdate = decoder.updateSync(cipherText);
169    // In GCM mode, pass in null in Cipher.doFinal in decryption. Verify the tag data passed in Cipher.init. If the verification fails, an exception will be thrown.
170    let decryptData = decoder.doFinalSync(null);
171    if (decryptData == null) {
172      console.info('GCM decrypt success, decryptData is null');
173    }
174    return decryptUpdate;
175  }
176  function genSymKeyByData(symKeyData: Uint8Array) {
177    let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData };
178    let aesGenerator = cryptoFramework.createSymKeyGenerator('AES128');
179    let symKey = aesGenerator.convertKeySync(symKeyBlob);
180    console.info('convertKeySync success');
181    return symKey;
182  }
183  function main() {
184    let keyData = new Uint8Array([83, 217, 231, 76, 28, 113, 23, 219, 250, 71, 209, 210, 205, 97, 32, 159]);
185    let symKey = genSymKeyByData(keyData);
186    let message = "This is a test";
187    let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) };
188    let encryptText = encryptMessage(symKey, plainText);
189    let decryptText = decryptMessage(symKey, encryptText);
190    if (plainText.data.toString() === decryptText.data.toString()) {
191      console.info('decrypt ok');
192      console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8'));
193    } else {
194      console.error('decrypt failed');
195    }
196  }
197  ```
198