• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params);
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