1# Encryption and Decryption with an SM4 Symmetric Key (GCM Mode) (ArkTS) 2 3 4For details about the algorithm specifications, see [SM4](crypto-sym-encrypt-decrypt-spec.md#sm4). 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, [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. 13 142. Use [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. The key type is **SM4_128**, 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.authTag](../../reference/apis-crypto-architecture-kit/js-apis-cryptoFramework.md#gcmparamsspec) 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 genGcmParamsSpec() { 50 let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 bytes 51 let dataIv = new Uint8Array(arr); 52 let ivBlob: cryptoFramework.DataBlob = { data: dataIv }; 53 arr = [0, 0, 0, 0, 0, 0, 0, 0]; // 8 bytes 54 let dataAad = new Uint8Array(arr); 55 let aadBlob: cryptoFramework.DataBlob = { data: dataAad }; 56 arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes 57 let dataTag = new Uint8Array(arr); 58 let tagBlob: cryptoFramework.DataBlob = { 59 data: dataTag 60 }; 61 // Obtain the GCM authTag from the doFinal result in encryption and fill it in the params parameter of Cipher.init in decryption. 62 let gcmParamsSpec: cryptoFramework.GcmParamsSpec = { 63 iv: ivBlob, 64 aad: aadBlob, 65 authTag: tagBlob, 66 algName: "GcmParamsSpec" 67 }; 68 return gcmParamsSpec; 69 } 70 71 let gcmParams = genGcmParamsSpec(); 72 73 // Encrypt the message. 74 async function encryptMessagePromise(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) { 75 let cipher = cryptoFramework.createCipher('SM4_128|GCM|PKCS7'); 76 await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, gcmParams); 77 let encryptUpdate = await cipher.update(plainText); 78 // In GCM mode, pass in null in cipher.doFinal in encryption. Obtain the tag data and fill it in the gcmParams object. 79 gcmParams.authTag = await cipher.doFinal(null); 80 return encryptUpdate; 81 } 82 // Decrypt the message. 83 async function decryptMessagePromise(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) { 84 let decoder = cryptoFramework.createCipher('SM4_128|GCM|PKCS7'); 85 await decoder.init(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, gcmParams); 86 let decryptUpdate = await decoder.update(cipherText); 87 // 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. 88 let decryptData = await decoder.doFinal(null); 89 if (decryptData == null) { 90 console.info('GCM decrypt success, decryptData is null'); 91 } 92 return decryptUpdate; 93 } 94 async function genSymKeyByData(symKeyData: Uint8Array) { 95 let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; 96 let sm4Generator = cryptoFramework.createSymKeyGenerator('SM4_128'); 97 let symKey = await sm4Generator.convertKey(symKeyBlob); 98 console.info('convertKey success'); 99 return symKey; 100 } 101 async function main() { 102 let keyData = new Uint8Array([83, 217, 231, 76, 28, 113, 23, 219, 250, 71, 209, 210, 205, 97, 32, 159]); 103 let symKey = await genSymKeyByData(keyData); 104 let message = "This is a test"; 105 let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) }; 106 let encryptText = await encryptMessagePromise(symKey, plainText); 107 let decryptText = await decryptMessagePromise(symKey, encryptText); 108 if (plainText.data.toString() === decryptText.data.toString()) { 109 console.info('decrypt ok'); 110 console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8')); 111 } else { 112 console.error('decrypt failed'); 113 } 114 } 115 ``` 116 117- Example (using synchronous APIs): 118 119 ```ts 120 import { cryptoFramework } from '@kit.CryptoArchitectureKit'; 121 import { buffer } from '@kit.ArkTS'; 122 123 124 function genGcmParamsSpec() { 125 let arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 12 bytes 126 let dataIv = new Uint8Array(arr); 127 let ivBlob: cryptoFramework.DataBlob = { data: dataIv }; 128 arr = [0, 0, 0, 0, 0, 0, 0, 0]; // 8 bytes 129 let dataAad = new Uint8Array(arr); 130 let aadBlob: cryptoFramework.DataBlob = { data: dataAad }; 131 arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; // 16 bytes 132 let dataTag = new Uint8Array(arr); 133 let tagBlob: cryptoFramework.DataBlob = { 134 data: dataTag 135 }; 136 // Obtain the GCM authTag from the doFinal result in encryption and fill it in the params parameter of init() in decryption. 137 let gcmParamsSpec: cryptoFramework.GcmParamsSpec = { 138 iv: ivBlob, 139 aad: aadBlob, 140 authTag: tagBlob, 141 algName: "GcmParamsSpec" 142 }; 143 return gcmParamsSpec; 144 } 145 146 let gcmParams = genGcmParamsSpec(); 147 148 // Encrypt the message. 149 function encryptMessage(symKey: cryptoFramework.SymKey, plainText: cryptoFramework.DataBlob) { 150 let cipher = cryptoFramework.createCipher('SM4_128|GCM|PKCS7'); 151 cipher.initSync(cryptoFramework.CryptoMode.ENCRYPT_MODE, symKey, gcmParams); 152 let encryptUpdate = cipher.updateSync(plainText); 153 // In GCM mode, pass in null in doFinal() in encryption. Obtain the tag data and fill it in the gcmParams object. 154 gcmParams.authTag = cipher.doFinalSync(null); 155 return encryptUpdate; 156 } 157 // Decrypt the message. 158 function decryptMessage(symKey: cryptoFramework.SymKey, cipherText: cryptoFramework.DataBlob) { 159 let decoder = cryptoFramework.createCipher('SM4_128|GCM|PKCS7'); 160 decoder.initSync(cryptoFramework.CryptoMode.DECRYPT_MODE, symKey, gcmParams); 161 let decryptUpdate = decoder.updateSync(cipherText); 162 // In GCM mode, pass in null in doFinal() in decryption. Verify the tag data passed in **init**. If the verification fails, an exception will be thrown. 163 let decryptData = decoder.doFinalSync(null); 164 if (decryptData == null) { 165 console.info('GCM decrypt success, decryptData is null'); 166 } 167 return decryptUpdate; 168 } 169 async function genSymKeyByData(symKeyData: Uint8Array) { 170 let symKeyBlob: cryptoFramework.DataBlob = { data: symKeyData }; 171 let sm4Generator = cryptoFramework.createSymKeyGenerator('SM4_128'); 172 let symKey = await sm4Generator.convertKey(symKeyBlob); 173 console.info('convertKey success'); 174 return symKey; 175 } 176 async function main() { 177 let keyData = new Uint8Array([83, 217, 231, 76, 28, 113, 23, 219, 250, 71, 209, 210, 205, 97, 32, 159]); 178 let symKey = await genSymKeyByData(keyData); 179 let message = "This is a test"; 180 let plainText: cryptoFramework.DataBlob = { data: new Uint8Array(buffer.from(message, 'utf-8').buffer) }; 181 let encryptText = encryptMessage(symKey, plainText); 182 let decryptText = decryptMessage(symKey, encryptText); 183 if (plainText.data.toString() === decryptText.data.toString()) { 184 console.info('decrypt ok'); 185 console.info('decrypt plainText: ' + buffer.from(decryptText.data).toString('utf-8')); 186 } else { 187 console.error('decrypt failed'); 188 } 189 } 190 ``` 191