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