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