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```