• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 消息认证码计算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
10HMAC通过指定摘要算法,以通信双方共享密钥与消息作为输入,生成消息认证码用于检验传递报文的完整性。HMAC在消息摘要算法的基础上增加了密钥的输入,确保了信息的正确性。生成的消息认证码为固定长度。
11
12## 开发步骤
13
14在调用update接口传入数据时,可以[一次性传入](#hmac一次性传入),也可以把数据人工[分段传入](#hmac分段传入)。对于同一段数据而言,是否分段,计算结果没有差异。对于数据量较大的数据,开发者可以根据实际需求选择是否分段传入。
15
16下面分别提供两种方式的示例代码。
17
18### HMAC(一次性传入)
19
201. 调用[OH_CryptoSymKeyGenerator_Create](../../reference/apis-crypto-architecture-kit/capi-crypto-sym-key-h.md#oh_cryptosymkeygenerator_create)、[OH_CryptoSymKeyGenerator_Generate](../../reference/apis-crypto-architecture-kit/capi-crypto-sym-key-h.md#oh_cryptosymkeygenerator_generate)生成密钥算法为HMAC的对称密钥(symKey)。
21
222. 调用[OH_CryptoMac_Create](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_create),指定字符串参数'HMAC',创建MAC算法为HMAC的MAC生成器。
23
243. 调用[OH_CryptoMac_SetParam](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_setparam),指定参数CRYPTO_MAC_DIGEST_NAME_STR,设置摘要算法名称。
25
264. 调用[OH_CryptoMac_Init](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_init),指定共享对称密钥(symKey),初始化MAC对象。
27
285. 调用[OH_CryptoMac_Update](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_update),传入自定义消息,进行消息认证码计算。
29
306. 调用[OH_CryptoMac_Final](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_final),获取MAC计算结果。
31
327. 调用[OH_CryptoMac_GetLength](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_getlength),获取MAC消息认证码的长度,单位为字节。
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    // 生成HMAC密钥,使用SM3作为摘要算法。
58    OH_CryptoSymKey *keyCtx = GenerateHmacKey("HMAC|SM3");
59    if (keyCtx == nullptr) {
60        return CRYPTO_OPERTION_ERROR;
61    }
62
63    // 创建HMAC生成器。
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    // 设置摘要算法名称为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    // 初始化HMAC计算。
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    // 一次性传入所有数据。
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    // 完成HMAC计算并获取结果。
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    // 获取HMAC值的长度。
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    // 清理资源。
127    OH_Crypto_FreeDataBlob(&out);
128    OH_CryptoMac_Destroy(ctx);
129    OH_CryptoSymKey_Destroy(keyCtx);
130    return CRYPTO_SUCCESS;
131}
132```
133
134### HMAC(分段传入)
135
136与一次性传入的步骤基本相同,区别在于多次调用[OH_CryptoMac_Update](../../reference/apis-crypto-architecture-kit/capi-crypto-mac-h.md#oh_cryptomac_update)来处理分段数据。
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    // 生成HMAC密钥,使用SM3作为摘要算法。
162    OH_CryptoSymKey *keyCtx = GenerateHmacKey("HMAC|SM3");
163    if (keyCtx == nullptr) {
164        return CRYPTO_OPERTION_ERROR;
165    }
166
167    // 创建HMAC生成器。
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    // 设置摘要算法名称为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    // 初始化HMAC计算。
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    // 分段传入数据。
197    const char *message = "aaaaa.....bbbbb.....ccccc.....ddddd.....eee";
198    size_t messageLen = strlen(message);
199    size_t segmentSize = 20; // 每段20字节。
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    // 完成HMAC计算并获取结果。
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    // 获取HMAC值的长度。
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    // 清理资源。
237    OH_Crypto_FreeDataBlob(&out);
238    OH_CryptoMac_Destroy(ctx);
239    OH_CryptoSymKey_Destroy(keyCtx);
240    return CRYPTO_SUCCESS;
241}
242```