• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Generating a CMAC (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
10A block cipher (such as AES) and a key are used to generate an authentication code, which verifies that a message has not been alerted during transmission.
11
12## How to Develop
13
14In the **update** API call, you can [pass in full data](#generating-a-cmac-by-passing-in-full-data) or [pass in data by segment](#generating-a-cmac-by-passing-in-data-by-segment). The same data will produce the same result no matter how the data is passed. Use the appropriate method based on the data size.
15
16The following provides examples of CMAC operations with different data passing methods.
17
18### Generating a CMAC by Passing in Full Data
19
201. Call [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 (**symKey**) with the key algorithm being AES-128.
21
222. Call [OH_CryptoMac_Create](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_create) and specify the string parameter **CMAC** to create a MAC generator with the CMAC algorithm.
23
243. Call [OH_CryptoMac_SetParam](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_setparam) and specify **CRYPTO_MAC_CIPHER_NAME_STR** to set the block cipher algorithm name.
25
264. Call [OH_CryptoMac_Init](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_init) and specify the shared symmetric key (**symKey**) to initialize the MAC object.
27
285. Call [OH_CryptoMac_Update](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_update) to pass in the data.
29
306. Call [OH_CryptoMac_Final](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_final) to obtain the MAC generation result.
31
327. Call [OH_CryptoMac_GetLength](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_getlength) to obtain the length of the MAC, in bytes.
33
34```C++
35#include "CryptoArchitectureKit/crypto_architecture_kit.h"
36#include <stdio.h>
37#include <string.h>
38
39static OH_CryptoSymKey *GenerateAesKey(const char *algoName)
40{
41    OH_CryptoSymKeyGenerator *keyGen = nullptr;
42    OH_Crypto_ErrCode ret = OH_CryptoSymKeyGenerator_Create(algoName, &keyGen);
43    if (ret != CRYPTO_SUCCESS) {
44        return nullptr;
45    }
46    OH_CryptoSymKey *keyCtx = nullptr;
47    ret = OH_CryptoSymKeyGenerator_Generate(keyGen, &keyCtx);
48    OH_CryptoSymKeyGenerator_Destroy(keyGen);
49    if (ret != CRYPTO_SUCCESS) {
50        return nullptr;
51    }
52    return keyCtx;
53}
54
55static OH_Crypto_ErrCode doTestCmacOnce()
56{
57    // Generate an AES-128 key.
58    OH_CryptoSymKey *keyCtx = GenerateAesKey("AES128");
59    if (keyCtx == nullptr) {
60        return CRYPTO_OPERTION_ERROR;
61    }
62
63    // Create a CMAC generator.
64    OH_CryptoMac *ctx = nullptr;
65    OH_Crypto_ErrCode ret = OH_CryptoMac_Create("CMAC", &ctx);
66    if (ret != CRYPTO_SUCCESS) {
67        OH_CryptoSymKey_Destroy(keyCtx);
68        return ret;
69    }
70
71    // Set the block cipher algorithm name to AES128.
72    const char *cipherName = "AES128";
73    Crypto_DataBlob cipherNameData = {
74        .data = reinterpret_cast<uint8_t *>(const_cast<char *>(cipherName)),
75        .len = strlen(cipherName)
76    };
77    ret = OH_CryptoMac_SetParam(ctx, CRYPTO_MAC_CIPHER_NAME_STR, &cipherNameData);
78    if (ret != CRYPTO_SUCCESS) {
79        OH_CryptoMac_Destroy(ctx);
80        OH_CryptoSymKey_Destroy(keyCtx);
81        return ret;
82    }
83
84    // Initialize the CMAC object.
85    ret = OH_CryptoMac_Init(ctx, keyCtx);
86    if (ret != CRYPTO_SUCCESS) {
87        OH_CryptoMac_Destroy(ctx);
88        OH_CryptoSymKey_Destroy(keyCtx);
89        return ret;
90    }
91
92    // Pass in full data.
93    const char *message = "cmacTestMessage";
94    Crypto_DataBlob input = {
95        .data = reinterpret_cast<uint8_t *>(const_cast<char *>(message)),
96        .len = strlen(message)
97    };
98    ret = OH_CryptoMac_Update(ctx, &input);
99    if (ret != CRYPTO_SUCCESS) {
100        OH_CryptoMac_Destroy(ctx);
101        OH_CryptoSymKey_Destroy(keyCtx);
102        return ret;
103    }
104
105    // Finalize CMAC generation and obtain the result.
106    Crypto_DataBlob out = {0};
107    ret = OH_CryptoMac_Final(ctx, &out);
108    if (ret != CRYPTO_SUCCESS) {
109        OH_CryptoMac_Destroy(ctx);
110        OH_CryptoSymKey_Destroy(keyCtx);
111        return ret;
112    }
113
114    // Obtain the length of the CMAC value.
115    uint32_t macLen = 0;
116    ret = OH_CryptoMac_GetLength(ctx, &macLen);
117    if (ret != CRYPTO_SUCCESS) {
118        OH_Crypto_FreeDataBlob(&out);
119        OH_CryptoMac_Destroy(ctx);
120        OH_CryptoSymKey_Destroy(keyCtx);
121        return ret;
122    }
123
124    printf("CMAC calculation success, length: %u\n", macLen);
125
126    // Free resources.
127    OH_Crypto_FreeDataBlob(&out);
128    OH_CryptoMac_Destroy(ctx);
129    OH_CryptoSymKey_Destroy(keyCtx);
130    return CRYPTO_SUCCESS;
131}
132```
133
134### Generating a CMAC by Passing in Data by Segment
135
136Unlike the first method, this one requires calling [OH_CryptoMac_Update](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_update) multiple times to process segmented data.
137
138```C++
139#include "CryptoArchitectureKit/crypto_architecture_kit.h"
140#include <stdio.h>
141#include <string.h>
142
143static OH_CryptoSymKey *GenerateAesKey(const char *algoName)
144{
145    OH_CryptoSymKeyGenerator *keyGen = nullptr;
146    OH_Crypto_ErrCode ret = OH_CryptoSymKeyGenerator_Create(algoName, &keyGen);
147    if (ret != CRYPTO_SUCCESS) {
148        return nullptr;
149    }
150    OH_CryptoSymKey *keyCtx = nullptr;
151    ret = OH_CryptoSymKeyGenerator_Generate(keyGen, &keyCtx);
152    OH_CryptoSymKeyGenerator_Destroy(keyGen);
153    if (ret != CRYPTO_SUCCESS) {
154        return nullptr;
155    }
156    return keyCtx;
157}
158
159static OH_Crypto_ErrCode doTestCmacBySegments()
160{
161    // Generate an AES-128 key.
162    OH_CryptoSymKey *keyCtx = GenerateAesKey("AES128");
163    if (keyCtx == nullptr) {
164        return CRYPTO_OPERTION_ERROR;
165    }
166
167    // Create a CMAC generator.
168    OH_CryptoMac *ctx = nullptr;
169    OH_Crypto_ErrCode ret = OH_CryptoMac_Create("CMAC", &ctx);
170    if (ret != CRYPTO_SUCCESS) {
171        OH_CryptoSymKey_Destroy(keyCtx);
172        return ret;
173    }
174
175    // Set the block cipher algorithm name to AES128.
176    const char *cipherName = "AES128";
177    Crypto_DataBlob cipherNameData = {
178        .data = reinterpret_cast<uint8_t *>(const_cast<char *>(cipherName)),
179        .len = strlen(cipherName)
180    };
181    ret = OH_CryptoMac_SetParam(ctx, CRYPTO_MAC_CIPHER_NAME_STR, &cipherNameData);
182    if (ret != CRYPTO_SUCCESS) {
183        OH_CryptoMac_Destroy(ctx);
184        OH_CryptoSymKey_Destroy(keyCtx);
185        return ret;
186    }
187
188    // Initialize the CMAC object.
189    ret = OH_CryptoMac_Init(ctx, keyCtx);
190    if (ret != CRYPTO_SUCCESS) {
191        OH_CryptoMac_Destroy(ctx);
192        OH_CryptoSymKey_Destroy(keyCtx);
193        return ret;
194    }
195
196    // Pass in data by segment.
197    const char *message = "aaaaa.....bbbbb.....ccccc.....ddddd.....eee";
198    size_t messageLen = strlen(message);
199    size_t segmentSize = 20; // Divide the data into segments of 20 bytes each.
200
201    for (size_t i = 0; i < messageLen; i += segmentSize) {
202        size_t currentSize = (i + segmentSize <= messageLen) ? segmentSize : (messageLen - i);
203        Crypto_DataBlob segment = {
204            .data = reinterpret_cast<uint8_t *>(const_cast<char *>(message + i)),
205            .len = currentSize
206        };
207        ret = OH_CryptoMac_Update(ctx, &segment);
208        if (ret != CRYPTO_SUCCESS) {
209            OH_CryptoMac_Destroy(ctx);
210            OH_CryptoSymKey_Destroy(keyCtx);
211            return ret;
212        }
213    }
214
215    // Finalize CMAC generation and obtain the result.
216    Crypto_DataBlob out = {0};
217    ret = OH_CryptoMac_Final(ctx, &out);
218    if (ret != CRYPTO_SUCCESS) {
219        OH_CryptoMac_Destroy(ctx);
220        OH_CryptoSymKey_Destroy(keyCtx);
221        return ret;
222    }
223
224    // Obtain the length of the CMAC value.
225    uint32_t macLen = 0;
226    ret = OH_CryptoMac_GetLength(ctx, &macLen);
227    if (ret != CRYPTO_SUCCESS) {
228        OH_Crypto_FreeDataBlob(&out);
229        OH_CryptoMac_Destroy(ctx);
230        OH_CryptoSymKey_Destroy(keyCtx);
231        return ret;
232    }
233
234    printf("CMAC calculation success, length: %u\n", macLen);
235
236    // Free resources.
237    OH_Crypto_FreeDataBlob(&out);
238    OH_CryptoMac_Destroy(ctx);
239    OH_CryptoSymKey_Destroy(keyCtx);
240    return CRYPTO_SUCCESS;
241}
242```
243