When I googled on how to perform the AES CMAC calculation using OpenSSL/libcrypto I couldn’t find any code example. I was no even sure that there was support for it of libcrypto so I downloaded the OpenSSL sources and dig into them until I found [crypto/cmac/cmac.c](/cmac/cmac.c](
https://github.com/openssl/openssl/blob/master/crypto/cmac/cmac.c). From there it was obvious that there is support for CMAC and that it follow the *{Init,Update,Final}
pattern found in EVP api. So I give it I try and I’m sharing the basic source code here for later reference:
// compile with | |
// cc `PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig" pkg-config --cflags --libs openssl` mac_example.c -o mac_example | |
// cc -I/usr/local/Cellar/openssl@1.1/1.1.1h/include -L/usr/local/Cellar/openssl@1.1/1.1.1h/lib -lssl -lcrypto mac_example.c | |
#include <stdio.h> | |
#include <openssl/cmac.h> | |
void printBytes(unsigned char *buf, size_t len) { | |
for(int i=0; i<len; i++) { | |
printf("%02x ", buf[i]); | |
} | |
printf("\n"); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
// https://tools.ietf.org/html/rfc4493 | |
// K, M and T from | |
// http://csrc.nist.gov/publications/nistpubs/800-38B/Updated_CMAC_Examples.pdf | |
// D.1 AES-128 | |
// K: 2b7e1516 28aed2a6 abf71588 09cf4f3c | |
unsigned char key[] = { 0x2b,0x7e,0x15,0x16, | |
0x28,0xae,0xd2,0xa6, | |
0xab,0xf7,0x15,0x88, | |
0x09,0xcf,0x4f,0x3c}; | |
// M: 6bc1bee2 2e409f96 e93d7e11 7393172a Mlen: 128 | |
unsigned char message[] = { 0x6b,0xc1,0xbe,0xe2, | |
0x2e,0x40,0x9f,0x96, | |
0xe9,0x3d,0x7e,0x11, | |
0x73,0x93,0x17,0x2a }; | |
unsigned char mact[16] = {0}; | |
size_t mactlen; | |
CMAC_CTX *ctx = CMAC_CTX_new(); | |
CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL); | |
printf("message length = %lu bytes (%lu bits)\n",sizeof(message), sizeof(message)*8); | |
CMAC_Update(ctx, message, sizeof(message)); | |
CMAC_Final(ctx, mact, &mactlen); | |
printBytes(mact, mactlen); | |
/* expected result T = 070a16b4 6b4d4144 f79bdd9d d04a287c */ | |
CMAC_CTX_free(ctx); | |
return 0; | |
} | |
I used the example data from NIST doc to validate the results.
The functions used are:
- CMAC_CTX_new: allocates a context
- CMAC_Init: configure the context to use AES-128-CBC
- CMAC_Update: Input the message, you can have several calls to it.
- CMAC_Final: Generate the CMAC
Unfortunately I believe that the CMAC implementation doesn’t make use of AES-NI. In other words it doesn’t make use of the hardware acceleration on Intel x86-64.