I managed to get CMAC to work using EVP interfaces. In addition, the key generation part that previously did not work is working. Here is the code. As you can see, I gave an example posted here: How to calculate AES CMAC using OpenSSL? Which uses OpenACL CMAC_Init / Update / Final interfaces and tried various NIST values ββto check if the EVP interfaces for CMAC work: Here is a code snippet. The key generation is also working now. Please let me know if there is something that I missed. I have a comment when using EVP. See also section below.
#include <stdio.h> #include <openssl/cmac.h> #include <openssl/err.h> #include <stdio.h> #include <stdlib.h> #include <openssl/evp.h> #include <string.h> typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; void printBytes(unsigned char *buf, size_t len) { int i; for(i=0; i<len; i++) { printf("%02x", buf[i]); } printf("\n"); } EVP_PKEY *generate_key(int type) { EVP_PKEY_CTX *pctx = NULL, *kctx = NULL; EVP_PKEY *params = NULL, *key = NULL; unsigned char k[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; /* Create context for the key generation */ if(!(kctx = EVP_PKEY_CTX_new_id(type, NULL))) goto err; /* Generate the key */ if(!EVP_PKEY_keygen_init(kctx)) goto err; if(type == EVP_PKEY_CMAC) { if (EVP_PKEY_CTX_ctrl(kctx, -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_CIPHER, 0, (void *)EVP_aes_256_cbc()) <= 0) goto err; if (EVP_PKEY_CTX_ctrl(kctx, -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_SET_MAC_KEY, sizeof(k), k) <= 0) goto err; } if (!EVP_PKEY_keygen(kctx, &key)) goto err; goto end; err: end: if(pctx) EVP_PKEY_CTX_free(pctx); if(params) EVP_PKEY_free(params); if(kctx) EVP_PKEY_CTX_free(kctx); return key; } void trial(uint8_t *msg, uint8_t mlen, uint8_t *key, uint8_t keylen, uint8_t **sig, uint8_t *slen) { //16 byte msg with 32 byte key with aes 256 cbc based CMAC if(!msg || !mlen || !key) { //handleError } if(*sig) OPENSSL_free(*sig); *sig = NULL; *slen = 0; EVP_MD_CTX* ctx = NULL; EVP_PKEY *pkey = NULL; const EVP_MD* md = NULL; OpenSSL_add_all_digests(); do { ctx = EVP_MD_CTX_create(); if(ctx == NULL) { printf("EVP_MD_CTX_create failed\n"); break; // failed } if(!(md = EVP_get_digestbyname("SHA256"))) printf("EVP_get_digestbyname failed\n"); printf("Over to EVP calls \n"); if(!(pkey = generate_key(EVP_PKEY_CMAC))) printf("Error 5 \n"); int rc ; rc = EVP_DigestSignInit(ctx, NULL, md, NULL, pkey); if(rc != 1) { printf("EVP_DigestSignInit failed\n"); ERR_print_errors_fp(stdout); break; } rc = EVP_DigestSignUpdate(ctx, msg, mlen); if(rc != 1) { printf("EVP_DigestSignUpdate failed\n"); ERR_print_errors_fp(stdout); break; } size_t req = 0; rc = EVP_DigestSignFinal(ctx, NULL, &req); if(rc != 1) { printf("EVP_DigestSignFinal failed\n"); ERR_print_errors_fp(stdout); break; } if(!(req > 0)) { printf("EVP_DigestSignFinal failed (2)\n"); break; } *sig = OPENSSL_malloc(req); if(*sig == NULL) { printf("OPENSSL_malloc failed, error \n"); break; } *slen = req; rc = EVP_DigestSignFinal(ctx, *sig, slen); if(rc != 1) { printf("EVP_DigestSignFinal failed (3)\n"); ERR_print_errors_fp(stdout); break; } } while(0); if(ctx) { EVP_MD_CTX_destroy(ctx); ctx = NULL; } } 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[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; // 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, 32, EVP_aes_256_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); uint8_t key_len = sizeof(key); uint8_t mlen = sizeof(message); uint8_t *dgst = NULL; size_t dlen; trial( message, mlen, key, key_len, &dgst, &dlen); printf("length of sig = %d\n", dlen); printf("CMAC returned from trial is: "); int i; for(i = 0; i < dlen; i++) printf("%02x", dgst[i]); printf("\n"); return 0; }
Comment:
As you can see from the code, it is important to note that when using EVP_DigestSignInit, the structure of the envelope of the message digest (EVP_MD) should not be interpreted as NULL, as indicated in the OpenSSL Wiki (ATLEAST for OpenSSL 1.0.2e, where I tested):
Note. There is no difference in the API between signing using an asymmetric algorithm and generating a MAC code. In the case of CMAC, no message digest function is required (can be passed NULL). signing using EVP_Sign * functions is very similar to the above example, except for the support of MAC codes. Please note that CMAC is only supported in the (not yet released) version 1.1.0 of OpenSSL.
If NULL is passed, I get a NULL error message. It seems that what is transmitted does not affect the generation of CMAC, since this structure is mostly ignored. I hope the guys from OpenSSL can clarify. Thanks!!