2

I want to compute a CMAC using OpenSSL. I found this question which helped me.

But I am encountering a problem with the following code:

#include <openssl/cmac.h>

void dispHex(const unsigned char *buffer, unsigned int size) {
    int i=0;

    for (i=0; i<size-1; i++) {
        printf("%02X ", buffer[i]);
    }
    printf("%02x\n", buffer[i]);
}

int main() {
    size_t out_len;
    unsigned char res[16];

    unsigned char mac_key[16] = { 0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07,
                            0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07};

    unsigned char msg[16] = { 0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07,
                            0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07};

    CMAC_CTX *cmac = CMAC_CTX_new();
    CMAC_Init(cmac, mac_key, 16, EVP_aes_128_cbc(), NULL);
    CMAC_Update(cmac, msg, sizeof(msg));
    CMAC_Final(cmac, res, &out_len);
    dispHex(res, sizeof(res));

    return 0;
}

I compile it with gcc -o test_cmac test_cmac_openssl.c -L C:/OpenSSL-Win32 -llibeay32 -I C:/OpenSSL-Win32/include and it produces test_cmac.exe without problem.

but when I run it (./test_cmac.exe), nothing happens. It just prints an empty line and stops:

xxx@DESKTOP /cygdrive/e/
$ ./test_cmac.exe

xx@DESKTOP /cygdrive/e/

Even if I add printf("..."); before the CMAC computation it goes the same way.

What is strange is that the following program:

#include <openssl/hmac.h>

void dispHex(const unsigned char *buffer, unsigned int size) {
    int i=0;

    for (i=0; i<size-1; i++) {
        printf("%02X ", buffer[i]);
    }
    printf("%02X\n", buffer[i]);
}

int main() {
    size_t out_len;
    unsigned char res[32];

    unsigned char mac_key[16] = { 0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07,
                            0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07};

    unsigned char msg[16] = { 0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07,
                            0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07};

    HMAC_CTX hmac;
    HMAC_CTX_init(&hmac);
    HMAC_Init_ex(&hmac, mac_key, 16, EVP_sha256(), NULL);
    HMAC_Update(&hmac, msg, sizeof(msg));
    HMAC_Final(&hmac, res, &out_len);
    dispHex(res, sizeof(res));

    return 0;

}

runs normally: after gcc -o test_hmac test_hmac_openssl.c -L C:/OpenSSL-Win32 -llibeay32 -I C:/OpenSSL-Win32/include and ./test_hmac.exe I get:

xxx@DESKTOP /cygdrive/e/
$ ./test_hmac.exe
...9A 21 F8 2D 60 84 6C 09 08 98 A5 1F 23 8C C8 8F C4 A9 0C C4 49 45 DA 10 B9 39 C0 93 C3 10 60 BE

xxx@DESKTOP /cygdrive/e/

So I'm a little confused... Why does it works with the HMAC primitive but not with the CMAC one? Does anybody already encountered this kind of problem?

I am using OpenSSL 32bit version: openssl version returns OpenSSL 1.0.2e 3 Dec 2015. I also checked that C:\OpenSSL-Win32\ is declared in the PATH environment variable.

Community
  • 1
  • 1
Raoul722
  • 1,222
  • 13
  • 30
  • 1
    You are also mixing/matching compilers. Shining Light's [Win32 OpenSSL](http://slproweb.com/products/Win32OpenSSL.html) use Microsoft's compiler, while you are using GCC. You should not do that. I'm kind of surprised that HMAC worked for you. – jww Feb 20 '16 at 20:04
  • how can that first program be 'compiles with out a problem'? it has a call to `printf()` which requires the `stdio.h` header file and that file is not #include'd. – user3629249 Feb 20 '16 at 20:09

2 Answers2

2

Looking at CMAC_Init, it appears initialization of the CMAC object is not performed because IMPL is NULL:

int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t  const EVP_CIPHER *cipher, ENGINE *IMPL)
if (!key && !cipher && !IMPL && keylen == 0) {
    /* Not initialised */
    if (ctx->nlast_block == -1)
        return 0;
    if (!EVP_EncryptInit_ex(ctx->cctx, NULL, NULL, NULL, zero_iv))
        return 0;
    memset(ctx->tbl, 0, EVP_CIPHER_CTX_block_size(ctx->cctx));
    ctx->nlast_block = 0;
    return 1;
}
jww
  • 97,681
  • 90
  • 411
  • 885
  • Good find; I don't think it was downvote worthy. I think `CMAC_CTX_new` performs the initialization of the context. The init you are looking at performs a "reinitialization" if using an engine. – jww Feb 20 '16 at 23:03
1

Why does it works with the HMAC primitive but not with the CMAC one? Does anybody already encountered this kind of problem?

I'm guessing most of the problems are due to mixing and matching compilers. Shining Light's Win32 OpenSSL use Microsoft's compiler, while you are using GCC. There's probably some mixing and matching of runtimes, too.

I'm kind of surprised the HMAC code worked as expected in the configuration. I guess you got lucky.

The following works for me, but there are some differences:

#include <openssl/evp.h>
#include <openssl/cmac.h>

#include <stdio.h>
#include <string.h>
#include <assert.h>

void dispHex(const unsigned char *buffer, unsigned int size) {
    unsigned int i=0;

    for (i=0; i<size; i++) {
        printf("%02X ", buffer[i]);
    }
    printf("\n");
}

int main() {
    int rc = 0;
    size_t out_len = 0;
    unsigned char res[EVP_MAX_MD_SIZE];

    unsigned char mac_key[16] = { 0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07,
                            0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07};

    unsigned char msg[16] = { 0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07,
                            0x00, 0x01 ,0x02 ,0x03, 0x04, 0x05, 0x06, 0x07};

    CMAC_CTX *cmac = CMAC_CTX_new();
    assert(cmac != NULL);

    rc = CMAC_Init(cmac, mac_key, sizeof(mac_key), EVP_aes_128_cbc(), NULL);
    assert(rc == 1);

    rc = CMAC_Update(cmac, msg, sizeof(msg));
    assert(rc == 1);

    rc = CMAC_Final(cmac, res, &out_len);
    assert(rc == 1);

    dispHex(res, out_len);

    CMAC_CTX_free(cmac);

    return 0;
}

The differences between your configuration and the one I used:

  1. The same compiler is used for both OpenSSL and the test program
  2. res is EVP_MAX_MD_SIZE in size
  3. CMAC_Init uses sizeof(mac_key)
  4. out_len is initialized
  5. displayHex uses out_len, and not sizeof(res)

Using sizeof(res) will print the 16 bytes of the MAC, and then print 16 garbage characters because res is declared as unsigned char res[32]. I don't think you got that far, so keep it in mind.


The program produces the following result. I don't know if this is the corrected/expected result, but it produces a result and prints it:

$ ./test.exe 
43 91 63 0E 47 4E 75 A6 2D 95 7A 04 1A E8 CC CC 

OpenSSL does not support Cygwin-x64, so you will need to use i686 version of things. Also see Issue #4326: Failed to configure for Cygwin-x64 on the OpenSSL Bug Tracker.

Here's how to build OpenSSL under Cygwin-x64. OpenSSL's build script has a few bends, so you can't use config. You have to use Configure and call out the triplet. The bug tracker issue is still valid because config is supposed to get things right.

$ curl https://www.openssl.org/source/openssl-1.0.2f.tar.gz -o openssl-1.0.2f.tar.gz
...
$ tar -xzf openssl-1.0.2f.tar.gz
...
$ cd openssl-1.0.2f

Then:

$ export KERNEL_BITS=64
$ ./Configure Cygwin-x86_64 shared no-ssl2 no-ssl3 --openssldir="$HOME/ssl"
...
$ make depend
...
$ make
...
$ make install_sw

install_sw installs the headers in $OPENSSLDIR/include, and the libraries in $OPENSSLDIR/lib. It does not install the man pages.

You then compile and link with:

$ gcc -I "$HOME/ssl/include" test.c -o test.exe "$HOME/ssl/lib/libcrypto.a"

Linking against libcrypto.a means you avoid library path problems. Things will "just work" for you.

Community
  • 1
  • 1
jww
  • 97,681
  • 90
  • 411
  • 885
  • Thanks a lot for your help. Your answer worked for me using Cygwin 64-bit. Finally I have to work with a 32-bit version and what is strange is that even if I use the OpenSSL version provided by Cygwin, I get the same problem. I will update my post to explain it. – Raoul722 Feb 22 '16 at 16:18
  • @Raoul722 - well, I just tested on 32-bit Cygwin-i686. I followed the steps above (modulo the new Configure triplet), and I got the same result. Everything works for me. – jww Feb 22 '16 at 16:37
  • 1
    @Raoul722 - I'm just guessing but you should abandon ***`-L`*** and ***`-l`***, and specify *exactly* what you want to link to. Stop letting the linker make the wrong decision. Do so by specifying the archive directly, like `"$HOME/ssl/lib/libcrypto.a"`. You might even need to open the Makefile and change it. I regularly modify makefiles because of issues like this. – jww Feb 22 '16 at 16:38
  • Thanks for the tip. Just want to notify that even by installing the openssl lib from the cygwin `setup-x86.exe`, I encounter the same problem that the one described in my question. Only recompiling it "manually" solved the problem. – Raoul722 Feb 22 '16 at 20:18