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