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