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 18In 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 // Define the decryption variables. 103 int decCnt = cipherLen / blockSize; 104 int decRem = cipherLen % blockSize; 105 int32_t plantLen = 0; 106 uint8_t plantText[OH_CRYPTO_MAX_TEST_DATA_LEN] = {0}; 107 108 // Generate a key. 109 OH_Crypto_ErrCode ret; 110 ret = OH_CryptoSymKeyGenerator_Create("AES128", &genCtx); 111 if (ret != CRYPTO_SUCCESS) { 112 goto end; 113 } 114 ret = OH_CryptoSymKeyGenerator_Generate(genCtx, &keyCtx); 115 if (ret != CRYPTO_SUCCESS) { 116 goto end; 117 } 118 119 // Set parameters. 120 ret = OH_CryptoSymCipherParams_Create(¶ms); 121 if (ret != CRYPTO_SUCCESS) { 122 goto end; 123 } 124 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_IV_DATABLOB, &ivBlob); 125 if (ret != CRYPTO_SUCCESS) { 126 goto end; 127 } 128 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_AAD_DATABLOB, &aadBlob); 129 if (ret != CRYPTO_SUCCESS) { 130 goto end; 131 } 132 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_TAG_DATABLOB, &tagInit); 133 if (ret != CRYPTO_SUCCESS) { 134 goto end; 135 } 136 137 // Encrypt data. 138 ret = OH_CryptoSymCipher_Create("AES128|GCM|PKCS7", &encCtx); 139 if (ret != CRYPTO_SUCCESS) { 140 goto end; 141 } 142 ret = OH_CryptoSymCipher_Init(encCtx, CRYPTO_ENCRYPT_MODE, keyCtx, params); 143 if (ret != CRYPTO_SUCCESS) { 144 goto end; 145 } 146 147 for (int i = 0; i < cnt; i++) { 148 msgBlob.len = blockSize; 149 ret = OH_CryptoSymCipher_Update(encCtx, &msgBlob, &encData); 150 if (ret != CRYPTO_SUCCESS) { 151 goto end; 152 } 153 msgBlob.data += blockSize; 154 memcpy(&cipherText[cipherLen], encData.data, encData.len); 155 cipherLen += encData.len; 156 } 157 if (rem > 0) { 158 msgBlob.len = rem; 159 ret = OH_CryptoSymCipher_Update(encCtx, (Crypto_DataBlob *)&msgBlob, &encData); 160 if (ret != CRYPTO_SUCCESS) { 161 goto end; 162 } 163 memcpy(&cipherText[cipherLen], encData.data, encData.len); 164 cipherLen += encData.len; 165 } 166 ret = OH_CryptoSymCipher_Final(encCtx, nullptr, &tag); 167 if (ret != CRYPTO_SUCCESS) { 168 goto end; 169 } 170 171 // Decrypt data. 172 cipherBlob = {.data = reinterpret_cast<uint8_t *>(cipherText), .len = (size_t)cipherLen}; 173 ret = OH_CryptoSymCipher_Create("AES128|GCM|PKCS7", &decCtx); 174 if (ret != CRYPTO_SUCCESS) { 175 goto end; 176 } 177 ret = OH_CryptoSymCipherParams_SetParam(params, CRYPTO_TAG_DATABLOB, &tag); 178 if (ret != CRYPTO_SUCCESS) { 179 goto end; 180 } 181 ret = OH_CryptoSymCipher_Init(decCtx, CRYPTO_DECRYPT_MODE, keyCtx, params); 182 if (ret != CRYPTO_SUCCESS) { 183 goto end; 184 } 185 for (int i = 0; i < decCnt; i++) { 186 cipherBlob.len = blockSize; 187 ret = OH_CryptoSymCipher_Update(decCtx, &cipherBlob, &decData); 188 if (ret != CRYPTO_SUCCESS) { 189 goto end; 190 } 191 cipherBlob.data += blockSize; 192 memcpy(&plantText[plantLen], decData.data, decData.len); 193 plantLen += decData.len; 194 } 195 if (decRem > 0) { 196 cipherBlob.len = decRem; 197 ret = OH_CryptoSymCipher_Update(decCtx, &cipherBlob, &decData); 198 if (ret != CRYPTO_SUCCESS) { 199 goto end; 200 } 201 memcpy(&plantText[plantLen], decData.data, decData.len); 202 plantLen += decData.len; 203 } 204 ret = OH_CryptoSymCipher_Final(decCtx, nullptr, &decData); 205 if (ret != CRYPTO_SUCCESS) { 206 goto end; 207 } 208 209end: 210 OH_CryptoSymCipherParams_Destroy(params); 211 OH_CryptoSymCipher_Destroy(encCtx); 212 OH_CryptoSymCipher_Destroy(decCtx); 213 OH_CryptoSymKeyGenerator_Destroy(genCtx); 214 OH_CryptoSymKey_Destroy(keyCtx); 215 OH_Crypto_FreeDataBlob(&encData); 216 OH_Crypto_FreeDataBlob(&tag); 217 OH_Crypto_FreeDataBlob(&decData); 218 return ret; 219} 220``` 221