【问题标题】:Unable to compute a CMAC using Cygwin and OpenSSL无法使用 Cygwin 和 OpenSSL 计算 CMAC
【发布时间】:2016-02-19 11:36:00
【问题描述】:

我想使用 OpenSSL 计算 CMAC。我找到了this question,这对我有帮助。

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

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

}

运行正常:在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 返回 OpenSSL 1.0.2e 3 Dec 2015。 我还检查了C:\OpenSSL-Win32\ 是否在 PATH 环境变量中声明。

【问题讨论】:

  • 您也在混合/匹配编译器。 Shining Light 的Win32 OpenSSL 使用Microsoft 的编译器,而您使用的是GCC。你不应该那样做。我很惊讶 HMAC 为您工作。
  • 第一个程序如何“编译没有问题”?它调用了printf(),这需要stdio.h 头文件并且该文件不是#include'd。

标签: c debugging openssl cryptography cygwin


【解决方案1】:

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

【讨论】:

  • 好发现;我认为这不值得投反对票。我认为CMAC_CTX_new 执行上下文的初始化。如果使用引擎,您正在查看的 init 会执行“重新初始化”。
【解决方案2】:

为什么它适用于 HMAC 原语而不适用于 CMAC 原语?有人遇到过这种问题吗?

我猜大部分问题是由于混合和匹配编译器造成的。 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]。我认为你没有做到这一点,所以请记住这一点。


程序产生以下结果。我不知道这是否是更正/预期的结果,但它会产生一个结果并打印出来:

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

OpenSSL does not support Cygwin-x64,所以你需要使用 i686 版本的东西。另请参阅 OpenSSL 错误跟踪器上的 Issue #4326: Failed to configure for Cygwin-x64

以下是在 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 中安装库。它不安装手册页。

然后你编译和链接:

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

链接libcrypto.a 意味着您可以避免库路径问题。一切都会为您“正常工作”。

【讨论】:

  • 非常感谢您的帮助。您的回答使用 Cygwin 64 位对我有用。最后我必须使用 32 位版本,奇怪的是,即使我使用 Cygwin 提供的 OpenSSL 版本,我也会遇到同样的问题。我会更新我的帖子来解释它。
  • @Raoul722 - 好吧,我刚刚在 32 位 Cygwin-i686 上进行了测试。我按照上面的步骤(以新的配置三元组为模),得到了相同的结果。一切都适合我。
  • @Raoul722 - 我只是在猜测,但你应该放弃 -L-l,然后准确地指定您要链接到的内容。停止让链接器做出错误的决定。通过直接指定存档来执行此操作,例如 "$HOME/ssl/lib/libcrypto.a"。您甚至可能需要打开 Makefile 并更改它。由于此类问题,我经常修改 makefile。
  • 感谢您的提示。只是想通知一下,即使从 cygwin setup-x86.exe 安装 openssl 库,我也会遇到与我的问题中描述的问题相同的问题。只有“手动”重新编译才能解决问题。
猜你喜欢
  • 1970-01-01
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多