无法使用 Cygwin 和 OpenSSL 计算 CMAC

Unable to compute a CMAC using Cygwin and OpenSSL

我想使用 OpenSSL 计算 CMAC。我发现 对我有帮助。

但是我遇到了以下代码的问题:

#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;
}

我用 gcc -o test_cmac test_cmac_openssl.c -L C:/OpenSSL-Win32 -llibeay32 -I C:/OpenSSL-Win32/include 编译它,它生成 test_cmac.exe 没有问题。

但是当我 运行 它 (./test_cmac.exe) 时,没有任何反应。它只是打印一个空行并停止:

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

xx@DESKTOP /cygdrive/e/

即使我在 CMAC 计算之前添加 printf("...");,它也会以相同的方式进行。

奇怪的是下面的程序:

#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;

}

运行s 通常:在 gcc -o test_hmac test_hmac_openssl.c -L C:/OpenSSL-Win32 -llibeay32 -I C:/OpenSSL-Win32/include./test_hmac.exe 之后我得到:

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/

所以我有点困惑...为什么它适用于 HMAC 原语而不适用于 CMAC 原语?有人遇到过这种问题吗?

我正在使用 OpenSSL 32 位版本:openssl version returns OpenSSL 1.0.2e 3 Dec 2015。 我还检查了 C:\OpenSSL-Win32\ 是否在 PATH 环境变量中声明。

查看 CMAC_Init,似乎未执行 CMAC 对象的初始化,因为 IMPLNULL:

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;
}

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

我猜大多数问题是由于混合和匹配编译器造成的。 Shining Light 的 Win32 OpenSSL 使用 Microsoft 的编译器,而您使用的是 GCC。运行时可能也有一些混合和匹配。

我有点惊讶 HMAC 代码在配置中按预期工作。我猜你走运了。

以下适用于我,但存在一些差异:

#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;
}

您的配置与我使用的配置之间的差异:

  1. OpenSSL 和测试程序使用相同的编译器
  2. res 尺寸 EVP_MAX_MD_SIZE
  3. CMAC_Init 使用 sizeof(mac_key)
  4. out_len 已初始化
  5. displayHex 使用 out_len,而不是 sizeof(res)

使用sizeof(res)将打印MAC的16个字节,然后打印16个垃圾字符,因为res被声明为unsigned char res[32]。我认为您还没有走到那一步,所以请记住这一点。


程序产生以下结果。我不知道这是否是 corrected/expected 结果,但它产生了一个结果并打印出来:

$ ./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 在 OpenSSL 错误跟踪器上。

以下是在 Cygwin-x64 下构建 OpenSSL 的方法。 OpenSSL 的构建脚本有一些弯曲,所以你不能使用 config。你得用Configure,叫出三连音。错误跟踪器问题仍然有效,因为 config 应该是正确的。

$ 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

然后:

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

install_sw$OPENSSLDIR/include 中安装头文件,在 $OPENSSLDIR/lib 中安装库。它不安装手册页。

然后编译并 link 使用:

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

针对 libcrypto.a 的链接意味着您可以避免库路径问题。事情会"just work"给你。