1# Encryption and Decryption by Segment with an AES Symmetric Key (GCM Mode) (C/C++) 2 3 4For details about the algorithm specifications, see [AES](crypto-sym-encrypt-decrypt-spec.md#aes). 5 6 7## Adding the Dynamic Library in the CMake Script 8```txt 9target_link_libraries(entry PUBLIC libohcrypto.so) 10``` 11 12## How to Develop 13 14**Creating an Object** 15 16Call [OH_CryptoSymKeyGenerator_Create](../../reference/apis-crypto-architecture-kit/_crypto_sym_key_api.md#oh_cryptosymkeygenerator_create) and [OH_CryptoSymKeyGenerator_Generate](../../reference/apis-crypto-architecture-kit/_crypto_sym_key_api.md#oh_cryptosymkeygenerator_generate) to generate a 128-bit AES symmetric key (**OH_CryptoSymKey**). 17 18 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-ndk.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. 19 20**Encrypting a Message** 21 221. Call [OH_CryptoSymCipher_Create](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_create) with the string parameter **'AES128|GCM|PKCS7'** to create a **Cipher** instance for encryption. The key type is **AES128**, block cipher mode is **GCM**, and the padding mode is **PKCS7**. 23 242. Call [OH_CryptoSymCipherParams_Create](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipherparams_create) to create a symmetric cipher parameter instance, and call [OH_CryptoSymCipherParams_SetParam](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipherparams_setparam) to set cipher parameters. 25 263. Call [OH_CryptoSymCipher_Init](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_init) to initialize the **Cipher** instance. Specifically, set **mode** to **CRYPTO_ENCRYPT_MODE**, and specify the key for encryption (**OH_CryptoSymKey**) and the encryption parameter instance (**OH_CryptoSymCipherParams**) corresponding to the GCM mode. 27 284. Set the size of the data to be passed in each time to 20 bytes, and call [OH_CryptoSymCipher_Update](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_update) multiple times to pass in the data (plaintext) to be encrypted. 29 30 - Currently, the amount of data to be passed in by a single **OH_CryptoSymCipher_Update()** is not limited. You can determine how to pass in data based on the data volume. 31 - You are advised to check the result of each **OH_CryptoSymCipher_Update()**. If the result is not **null**, obtain the data and combine the data segments into complete ciphertext. The **OH_CryptoSymCipher_Update()** result may vary with the key specifications. 32 33 If a block cipher mode (ECB or CBC) is used, data is encrypted and output based on the block size. That is, if the data of an **OH_CryptoSymCipher_Update()** operation matches the block size, the ciphertext is output. Otherwise, **null** is output, and the plaintext will be combined with the input data of the next **OH_CryptoSymCipher_Update()** to form a block. When **OH_CryptoSymCipher_Final()** is called, the unencrypted data is padded to the block size based on the specified padding mode, and then encrypted. The **OH_CryptoSymCipher_Update()** API works in the same way in decryption. 34 35 If a stream cipher mode (CTR or OFB) is used, the ciphertext length is usually the same as the plaintext length. 36 376. Call [OH_CryptoSymCipher_Final](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_final) to generate the ciphertext. 38 39 - If data has been passed in by **OH_CryptoSymCipher_Update()**, pass in **null** in the **data** parameter of **OH_CryptoSymCipher_Final**. 40 - The output of **OH_CryptoSymCipher_Final** may be **null**. To avoid exceptions, always check whether the result is **null** before accessing specific data. 41 > **NOTE**<br> 42 > If GCM mode is used, **authTag** returned by **OH_CryptoSymCipher_Final()** will be used to initialize the authentication information during decryption and needs to be saved. 43 > In GCM mode, **authTag** must be of 16 bytes. It is used as the authentication information during decryption. In the example, **authTag** is of 16 bytes. 44 45 46**Decrypting a Message** 47 481. Call [OH_CryptoSymCipher_Create](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_create) with the string parameter **'AES128|GCM|PKCS7'** to create a **Cipher** instance for decryption. The key type is **AES128**, block cipher mode is **GCM**, and the padding mode is **PKCS7**. 49 502. Call [OH_CryptoSymCipherParams_SetParam](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipherparams_setparam) to set **authTag** as the authentication information for decryption. 51 52 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. 53 543. Call [OH_CryptoSymCipher_Init](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_init) to initialize the **Cipher** instance. Specifically, set **mode** to **CRYPTO_DECRYPT_MODE**, and specify the key for decryption (**OH_CryptoSymKey**) and the decryption parameter instance (**OH_CryptoSymCipherParams**) corresponding to the GCM mode. 55 564. Set the size of the data to be passed in each time to 20 bytes, and call [OH_CryptoSymCipher_Update](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_update) multiple times to pass in the data (ciphertext) to be decrypted. 57 585. Call [OH_CryptoSymCipher_Final](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_final) to generate the plaintext. 59 60**Destroying Objects** 61 62Call [OH_CryptoSymKeyGenerator_Destroy](../../reference/apis-crypto-architecture-kit/_crypto_sym_key_api.md#oh_cryptosymkeygenerator_destroy), [OH_CryptoSymCipher_Destroy](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipher_destroy), and [OH_CryptoSymCipherParams_Destroy](../../reference/apis-crypto-architecture-kit/_crypto_sym_cipher_api.md#oh_cryptosymcipherparams_destroy) to destroy the instances created. 63 64 65**Example** 66 67```c++ 68#include <string.h> 69#include "CryptoArchitectureKit/crypto_common.h" 70#include "CryptoArchitectureKit/crypto_sym_cipher.h" 71 72#define OH_CRYPTO_GCM_TAG_LEN 16 73#define OH_CRYPTO_MAX_TEST_DATA_LEN 128 74static OH_Crypto_ErrCode doTestAesGcmSeg() 75{ 76 OH_CryptoSymKeyGenerator *genCtx = nullptr; 77 OH_CryptoSymCipher *encCtx = nullptr; 78 OH_CryptoSymCipher *decCtx = nullptr; 79 OH_CryptoSymKey *keyCtx = nullptr; 80 OH_CryptoSymCipherParams *params = nullptr; 81 82 char *plainText = const_cast<char *>("aaaaa.....bbbbb.....ccccc.....ddddd.....eee"); 83 Crypto_DataBlob msgBlob = {.data = (uint8_t *)(plainText), .len = strlen(plainText)}; 84 85 uint8_t aad[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 86 uint8_t tagArr[16] = {0}; 87 uint8_t iv[12] = {1, 2, 4, 12, 3, 4, 2, 3, 3, 2, 0, 4}; // iv is generated from an array of secure random numbers. 88 Crypto_DataBlob tag = {.data = nullptr, .len = 0}; 89 Crypto_DataBlob ivBlob = {.data = iv, .len = sizeof(iv)}; 90 Crypto_DataBlob aadBlob = {.data = aad, .len = sizeof(aad)}; 91 Crypto_DataBlob encData = {.data = nullptr, .len = 0}; 92 Crypto_DataBlob decData = {.data = nullptr, .len = 0}; 93 Crypto_DataBlob tagInit = {.data = tagArr, .len = sizeof(tagArr)}; 94 int32_t cipherLen = 0; 95 int blockSize = 20; 96 int32_t randomLen = strlen(plainText); 97 Crypto_DataBlob cipherBlob; 98 // Define the encryption variables. 99 int cnt = randomLen / blockSize; 100 int rem = randomLen % blockSize; 101 uint8_t cipherText[OH_CRYPTO_MAX_TEST_DATA_LEN] = {0}; 102 103 // Define the decryption variables. 104 int decCnt = cipherLen / blockSize; 105 int decRem = cipherLen % blockSize; 106 int32_t plantLen = 0; 107 uint8_t plantText[OH_CRYPTO_MAX_TEST_DATA_LEN] = {0}; 108 109 // Generate a key. 110 OH_Crypto_ErrCode ret; 111 ret = OH_CryptoSymKeyGenerator_Create("AES128", &genCtx); 112 if (ret != CRYPTO_SUCCESS) { 113 goto end; 114 } 115 ret = OH_CryptoSymKeyGenerator_Generate(genCtx, &keyCtx); 116 if (ret != CRYPTO_SUCCESS) { 117 goto end; 118 } 119 120 // Set parameters. 121 ret = OH_CryptoSymCipherParams_Create(¶ms); 122 if (ret != CRYPTO_SUCCESS) { 123 goto end; 124 } 125 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_IV_DATABLOB, &ivBlob); 126 if (ret != CRYPTO_SUCCESS) { 127 goto end; 128 } 129 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_AAD_DATABLOB, &aadBlob); 130 if (ret != CRYPTO_SUCCESS) { 131 goto end; 132 } 133 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_TAG_DATABLOB, &tagInit); 134 if (ret != CRYPTO_SUCCESS) { 135 goto end; 136 } 137 138 // Encrypt data. 139 ret = OH_CryptoSymCipher_Create("AES128|GCM|PKCS7", &encCtx); 140 if (ret != CRYPTO_SUCCESS) { 141 goto end; 142 } 143 ret = OH_CryptoSymCipher_Init(encCtx, CRYPTO_ENCRYPT_MODE, keyCtx, params); 144 if (ret != CRYPTO_SUCCESS) { 145 goto end; 146 } 147 148 for (int i = 0; i < cnt; i++) { 149 msgBlob.len = blockSize; 150 ret = OH_CryptoSymCipher_Update(encCtx, &msgBlob, &encData); 151 if (ret != CRYPTO_SUCCESS) { 152 goto end; 153 } 154 msgBlob.data += blockSize; 155 memcpy(&cipherText[cipherLen], encData.data, encData.len); 156 cipherLen += encData.len; 157 } 158 if (rem > 0) { 159 msgBlob.len = rem; 160 ret = OH_CryptoSymCipher_Update(encCtx, (Crypto_DataBlob *)&msgBlob, &encData); 161 if (ret != CRYPTO_SUCCESS) { 162 goto end; 163 } 164 memcpy(&cipherText[cipherLen], encData.data, encData.len); 165 cipherLen += encData.len; 166 } 167 ret = OH_CryptoSymCipher_Final(encCtx, nullptr, &tag); 168 if (ret != CRYPTO_SUCCESS) { 169 goto end; 170 } 171 172 // Decrypt data. 173 cipherBlob = {.data = reinterpret_cast<uint8_t *>(cipherText), .len = (size_t)cipherLen}; 174 ret = OH_CryptoSymCipher_Create("AES128|GCM|PKCS7", &decCtx); 175 if (ret != CRYPTO_SUCCESS) { 176 goto end; 177 } 178 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_TAG_DATABLOB, &tag); 179 if (ret != CRYPTO_SUCCESS) { 180 goto end; 181 } 182 ret = OH_CryptoSymCipher_Init(decCtx, CRYPTO_DECRYPT_MODE, keyCtx, params); 183 if (ret != CRYPTO_SUCCESS) { 184 goto end; 185 } 186 for (int i = 0; i < decCnt; i++) { 187 cipherBlob.len = blockSize; 188 ret = OH_CryptoSymCipher_Update(decCtx, &cipherBlob, &decData); 189 if (ret != CRYPTO_SUCCESS) { 190 goto end; 191 } 192 cipherBlob.data += blockSize; 193 memcpy(&plantText[plantLen], decData.data, decData.len); 194 plantLen += decData.len; 195 } 196 if (decRem > 0) { 197 cipherBlob.len = decRem; 198 ret = OH_CryptoSymCipher_Update(decCtx, &cipherBlob, &decData); 199 if (ret != CRYPTO_SUCCESS) { 200 goto end; 201 } 202 memcpy(&plantText[plantLen], decData.data, decData.len); 203 plantLen += decData.len; 204 } 205 ret = OH_CryptoSymCipher_Final(decCtx, nullptr, &decData); 206 if (ret != CRYPTO_SUCCESS) { 207 goto end; 208 } 209 210end: 211 OH_CryptoSymCipherParams_Destroy(params); 212 OH_CryptoSymCipher_Destroy(encCtx); 213 OH_CryptoSymCipher_Destroy(decCtx); 214 OH_CryptoSymKeyGenerator_Destroy(genCtx); 215 OH_CryptoSymKey_Destroy(keyCtx); 216 OH_Crypto_FreeDataBlob(&encData); 217 OH_Crypto_FreeDataBlob(&tag); 218 OH_Crypto_FreeDataBlob(&decData); 219 return ret; 220} 221``` 222