V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dtsdao
V2EX  ›  程序员

用 tinyAES 加密跨平台运行结果不同

  •  
  •   dtsdao · 2020-03-17 20:51:08 +08:00 · 2753 次点击
    这是一个创建于 1712 天前的主题,其中的信息可能已经有所发展或是发生改变。
    代码: https://paste.ubuntu.com/p/nGBZxQ4sbY
    引用的 AES 库: https://github.com/kokke/tiny-AES-c
    引用的 MD5 库: https://bobobobo.wordpress.com/2010/10/17/md5-c-implementation/

    大概的意思就是用 AES 加密然后获取 MD5

    在 MinGW/Linux 编译运行后相同的输入结果总是有差别,问题究竟出在哪呢?

    或者,该怎样用其他语言改写这段代码?
    第 1 条附言  ·  2020-03-17 21:52:16 +08:00

    贴一下反编译出来的源码

    code

    int v22; int v42;

    unsigned int v29;

    char *v19; char *v30;

    _BYTE v38[3];

    21 条回复    2020-03-18 00:59:04 +08:00
    lcdtyph
        1
    lcdtyph  
       2020-03-17 20:59:32 +08:00
    因为加密完 text 存储的已经不是字符串了啊,没有\0 做结尾了。所以 digestString 很有可能读到不属于 text 的值。你要用的是
    md5.digestMemory((char *)text, sizeof text);
    dtsdao
        2
    dtsdao  
    OP
       2020-03-17 21:12:45 +08:00
    @lcdtyph text 数组我自认为已经开的挺大了,之前开小了连 windows 结果都不正确
    说实话,我觉得用 C++写这个真的头疼,这段是反编译出来的所以看着特别难受,用其它语言改写总是结果不对
    lcdtyph
        3
    lcdtyph  
       2020-03-17 21:24:42 +08:00
    @dtsdao #2 结果都不正确原因是 digestString 不知道读到哪里才停止啊,如果你加密之后的数据里没有'\0'或者'\0'在中间就出现了你的 md5 结果肯定不对啊,这和你 text 数组开多大有什么关系呢?
    BrettD
        4
    BrettD  
       2020-03-17 21:29:05 +08:00 via iPhone
    是不是逻辑写错了
    dtsdao
        5
    dtsdao  
    OP
       2020-03-17 21:34:58 +08:00
    @lcdtyph 我试了一下用 digestMemory,运行结果还是不一样。

    Line 27: puts(md5.digestMemory(text, sizeof text));

    input:test1234

    Linux:a54e0cfdb3158654122d193cdf29c6e5
    Windows:fb4c2c022c39db620d88476666f5f79a
    dtsdao
        6
    dtsdao  
    OP
       2020-03-17 21:36:19 +08:00
    @BrettD 逻辑不是我写的,是反编译的。Windows 跑得很好,Linux 就不行了。源程序是用的 NDK 生成的 arm 的 so,我手里没有源码。
    sfqtsh
        7
    sfqtsh  
       2020-03-17 21:44:19 +08:00 via Android
    1 换行符\r\n
    2 getchar 的返回类型是 int
    lcdtyph
        8
    lcdtyph  
       2020-03-17 21:49:54 +08:00
    @dtsdao #5
    我编译一下试试看
    还有一个问题是你这么短的输入,那个 aes_ecb_encrypt 根本就没机会运行
    dtsdao
        9
    dtsdao  
    OP
       2020-03-17 21:57:30 +08:00
    @sfqtsh 1.都是在 bash 环境运行,换行符统一\n 2.强制转换就转换吧,我快读多少年来都这么写的
    dtsdao
        10
    dtsdao  
    OP
       2020-03-17 22:27:37 +08:00
    ...重新反编译了一下发现贴的代码变量类型不太对,详见下图吧

    https://i.loli.net/2020/03/17/OJY7bdoK9xwnjB2.png
    springz
        11
    springz  
       2020-03-17 22:35:34 +08:00
    问问题好歹给一个最小可复现,再说反编译,额。总是想到不好的事情。
    dtsdao
        12
    dtsdao  
    OP
       2020-03-17 22:42:33 +08:00
    @springz 已经给了复现方案,所有源码都能获取到。这是已弃用的内部软件的源码,不要想多。
    lcdtyph
        13
    lcdtyph  
       2020-03-17 22:50:51 +08:00   ❤️ 1
    @dtsdao #12
    我吐了,md5.h 里面有一行 typedef unsigned long int UINT4;
    这导致 UINT4 在 64 位 unix 机器上根本不是 4byte,而是 8byte。而 win 上 long 总是 4byte 的所以 win 上的结果是对的。
    lcdtyph
        14
    lcdtyph  
       2020-03-17 23:01:38 +08:00
    你可以把那行改成
    #include <stdint.h>
    typedef uint32_t UINT4;
    dtsdao
        15
    dtsdao  
    OP
       2020-03-17 23:11:57 +08:00
    @lcdtyph 草,我就猜是这样,我还以为是 uint_8 的事呢,结果查了半天 tinyaes 相关问题都没查出来,感谢您帮忙定位,这个库太坑了。顺便求下用其他库改写的源码,这个真的看着太丑了。

    问题相关: https://stackoverflow.com/questions/697361/md5-hash-calculates-differently-on-server
    lcdtyph
        16
    lcdtyph  
       2020-03-17 23:23:54 +08:00
    @dtsdao #15
    我比较熟悉 openssl……
    不过如果你运行在嵌入式设备的话可以用 mbedtls
    我写个 demo
    dtsdao
        17
    dtsdao  
    OP
       2020-03-17 23:30:29 +08:00
    话说写这个玩意的人貌似根本就没管 AES 的 Padding 之类的吧,我觉得它能运行都很神奇,要不是登录校验需要的话打死不会用 C 复现的...
    lcdtyph
        18
    lcdtyph  
       2020-03-18 00:07:35 +08:00
    @dtsdao #15
    ```
    #include <stdio.h>

    #include <mbedtls/md.h>
    #include <mbedtls/cipher.h>

    uint8_t text[80] = {'t', 'e', 's', 't', '1', '2', '3', '4'};

    int main()
    {
    uint8_t buf[16] = {0};

    mbedtls_md_context_t md5;
    mbedtls_md_init_ctx(&md5, mbedtls_md_info_from_type(MBEDTLS_MD_MD5));

    mbedtls_md_starts(&md5);

    mbedtls_md_update(&md5, text, sizeof text);

    mbedtls_md_finish(&md5, buf);

    for (int i = 0; i < sizeof buf; ++i) {
    printf("%02hhx", buf[i]);
    }
    printf("\n");

    return 0;
    }
    ```
    dtsdao
        19
    dtsdao  
    OP
       2020-03-18 00:13:16 +08:00
    @lcdtyph 我说的倒不是 MD5,主要是前面那块 AES,直接用 AES_ECB_encrypt 就对,加了 padding 就错,如果能用 openssl 改写就好了
    lcdtyph
        20
    lcdtyph  
       2020-03-18 00:49:19 +08:00
    @dtsdao #19
    ECB 模式无所谓 padding,因为他默认输入是 16byte 的整数倍,就是要求自己 padding。在你的代码里其实就相当于 zero padding

    ```
    #include <stdio.h>
    #include <stdint.h>
    #include <string.h>

    #include <mbedtls/md.h>
    #include <mbedtls/cipher.h>

    uint8_t key[] = "88a2a91ee2126bfd";
    uint8_t text[80] = {'t', 'e', 's', 't', '1', '2', '3', '4'};
    uint8_t len = 0;

    int main()
    {
    mbedtls_cipher_context_t ctx;

    mbedtls_cipher_init(&ctx);
    mbedtls_cipher_setup(&ctx, mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB));

    mbedtls_cipher_setkey(&ctx, key, 128, MBEDTLS_ENCRYPT);
    mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_ZEROS);

    uint8_t buf[80];
    size_t olen = sizeof buf;
    size_t idx = 0;
    mbedtls_cipher_update(&ctx, text, 16, buf + idx, &olen);
    idx += olen;
    olen = (sizeof buf) - idx;
    mbedtls_cipher_finish(&ctx, buf + idx, &olen);
    idx += olen;

    mbedtls_cipher_free(&ctx);

    for (int i = 0; i < idx; ++i) {
    printf("%02hhx", buf[i]);
    }
    printf("\n");

    return 0;
    }
    ```

    ECB 模式其实也不需要上面的 mbedtls_cipher_finish,但是为了过程完整我还是写出来了
    dtsdao
        21
    dtsdao  
    OP
       2020-03-18 00:59:04 +08:00
    @lcdtyph 感谢!
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2642 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 02:48 · PVG 10:48 · LAX 18:48 · JFK 21:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.