• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Generating an HMAC (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 hash-based message authentication code (HMAC) uses a specified digest algorithm to generate a MAC based on the key and message shared by communicating parties. The MAC is used to check the integrity of transmitted packets. The HMAC adds key input on the basis of the message digest algorithm to ensure information correctness. The generated MAC has a fixed length.
11
12## How to Develop
13
14In the **update** API call, you can [pass in full data](#generating-an-hmac-by-passing-in-full-data) or [pass in data by segment](#generating-an-hmac-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 with different data passing methods.
17
18### Generating an HMAC 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 HMAC.
21
222. Call [OH_CryptoMac_Create](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_create) and specify the string parameter **HMAC** to create a MAC generator with the HMAC algorithm.
23
243. Call [OH_CryptoMac_SetParam](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_setparam) and specify **CRYPTO_MAC_DIGEST_NAME_STR** to set the digest 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 *GenerateHmacKey(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 doTestHmacOnce()
56{
57    // Generate an HMAC key, using SM3 as the digest algorithm.
58    OH_CryptoSymKey *keyCtx = GenerateHmacKey("HMAC|SM3");
59    if (keyCtx == nullptr) {
60        return CRYPTO_OPERTION_ERROR;
61    }
62
63    // Create an HMAC generator.
64    OH_CryptoMac *ctx = nullptr;
65    OH_Crypto_ErrCode ret = OH_CryptoMac_Create("HMAC", &ctx);
66    if (ret != CRYPTO_SUCCESS) {
67        OH_CryptoSymKey_Destroy(keyCtx);
68        return ret;
69    }
70
71    // Set the digest algorithm name to SM3.
72    const char *digestName = "SM3";
73    Crypto_DataBlob digestNameData = {
74        .data = reinterpret_cast<uint8_t *>(const_cast<char *>(digestName)),
75        .len = strlen(digestName)
76    };
77    ret = OH_CryptoMac_SetParam(ctx, CRYPTO_MAC_DIGEST_NAME_STR, &digestNameData);
78    if (ret != CRYPTO_SUCCESS) {
79        OH_CryptoMac_Destroy(ctx);
80        OH_CryptoSymKey_Destroy(keyCtx);
81        return ret;
82    }
83
84    // Initialize the HMAC 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 = "hmacTestMessage";
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 HMAC 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 HMAC 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("HMAC 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 an HMAC 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 *GenerateHmacKey(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 doTestHmacBySegments()
160{
161    // Generate an HMAC key, using SM3 as the digest algorithm.
162    OH_CryptoSymKey *keyCtx = GenerateHmacKey("HMAC|SM3");
163    if (keyCtx == nullptr) {
164        return CRYPTO_OPERTION_ERROR;
165    }
166
167    // Create an HMAC generator.
168    OH_CryptoMac *ctx = nullptr;
169    OH_Crypto_ErrCode ret = OH_CryptoMac_Create("HMAC", &ctx);
170    if (ret != CRYPTO_SUCCESS) {
171        OH_CryptoSymKey_Destroy(keyCtx);
172        return ret;
173    }
174
175    // Set the digest algorithm name to SM3.
176    const char *digestName = "SM3";
177    Crypto_DataBlob digestNameData = {
178        .data = reinterpret_cast<uint8_t *>(const_cast<char *>(digestName)),
179        .len = strlen(digestName)
180    };
181    ret = OH_CryptoMac_SetParam(ctx, CRYPTO_MAC_DIGEST_NAME_STR, &digestNameData);
182    if (ret != CRYPTO_SUCCESS) {
183        OH_CryptoMac_Destroy(ctx);
184        OH_CryptoSymKey_Destroy(keyCtx);
185        return ret;
186    }
187
188    // Initialize the HMAC 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 HMAC 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 HMAC 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("HMAC 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