wohenyingyu01
V2EX  ›  C

同样一份 c 代码,用 oc 调用的结果和直接 gcc 编译运行的结果不一样是为什么

  •  
  •   wohenyingyu01 · Jan 24, 2016 · 3522 views
    This topic created in 3940 days ago, the information mentioned may be changed or developed.

    主要在做 aes 加密这块,因为涉及到服务器,安卓和 iOS 的多平台,试过很多的库,同样的 aes - 256-cbc 算法,不同语言的库加密出来的结果都不一样,也不能互相解密,故想用同一个 c 语言库跨平台运行。 main 函数如下:

    int m, n, i, j;
    char c;
    aes_context ctx;
    unsigned char buf[32];
    unsigned char key[32];

    n=2;
    memset(key,0,32);
    

    memcpy(key,(unsigned char)"test",32);
    memset(buf,0,32);
    memcpy(buf,(unsigned char
    )"13911112222+1234567890+313787",32);
    aes_set_key( &ctx, key, 128 + n*64);
    aes_encrypt( &ctx, buf, buf );
    printf("The encrypted data is:\n");
    for(i=0;i<32;i++)
    {
    printf("%02x",buf[i]);
    }
    printf("\n");
    printf("\n");

    aes_set_key( &ctx, key, 128 + n * 64 );
    aes_decrypt( &ctx, buf, buf );
    printf("The decrypted data is:\n");
    
    printf("%s",buf);
    printf("\n");
    return( 0 );
    

    问题来了,当我在 gcc 下运行此 main 函数的结果是
    The encrypted data is:
    bd704722da9e2e97de83a43ab442fb693536373839302b333133373837303000

    The decrypted data is:
    13911112222+1234567890+31378700

    当我将 main 函数改为普通函数,在 xcode 用 swift 调用 oc 去调用这个函数,在不传递任何参数进去的情况下,结果为:

    The encrypted data is:
    562591cb7184ec79998f411268d751423536373839302b333133373837000000

    The decrypted data is:
    13911112222+1234567890+313787

    同样的代码,没有任何改变,为何会运行出两种结果?而且解密只能在同一个函数下解密成功,出了这个函数这个密闻就再也无法解密了,是库有问题吗?求推荐跨平台 aes 库……

    38 replies  •  2016-01-25 16:58:59 +08:00
    zhicheng
    zhicheng
    Jan 24, 2016❤️1
    1
    memcpy(key,(unsigned char)"test",32);

    这行 memcpy 很是酸爽。
    w2exzz
    w2exzz
    Jan 24, 2016 via Android
    2
    1 楼说得对……这里出现了随机数据
    am241
    am241
    Jan 24, 2016
    3
    这算是下标越界吧
    ilotuo
    ilotuo
    Jan 24, 2016 via Android❤️1
    4
    内存操作错误 导致变量或者函数指针乱了
    我也遇过类似的
    codecrash
    codecrash
    Jan 25, 2016 via Android
    5
    我遇到过同样一份代码 vc 和 gcc 编译都能通过,但是 vc 的会崩溃,一直不明原因。后来调试发现, vc 编译的东西对象的析构顺序和 gcc 不一样,这导致了空指针的出现,所以就无法正常运行了。
    catlove
    catlove
    Jan 25, 2016
    6
    看到这行我就醉了。。。。
    catlove
    catlove
    Jan 25, 2016❤️1
    7
    memcpy(key,(unsigned char)"test",32);
    看到这行我就醉了。。。。
    jukka
    jukka
    Jan 25, 2016
    8
    man memcpy 了之后再来写代码。
    kobe1941
    kobe1941
    Jan 25, 2016❤️1
    9
    @catlove
    函数原型:
    void *memcpy(void *dest, const void *src, size_t n);

    功能:
    从源 src 所指的内存地址的起始位置开始拷贝 n 个字节到目标 dest 所指的内存地址的起始位置中

    楼主的操作每次都从随机地址开始拷贝。
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    10
    @zhicheng
    @kobe1941
    @catlove

    我知道越界了,但是我用 xcode 调试工具仔细看过了,每次运行到这里的时候超过 test 的部分会自动用\0 补全,就没动它,因为是上门给的使用例子……
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    11
    @wohenyingyu01 而且每次同一环境运行的结果也是固定的……
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    12
    @wohenyingyu01 打错了,上面给的
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    13
    @kobe1941
    @zhicheng
    @jukka
    我又看了一遍发现明明是 memset(buf,0,32); 初始化过一遍了,怎么会出现随机数字,我虽然不会 c 但是不要框我啊😰
    xujif
    xujif
    Jan 25, 2016
    14
    @wohenyingyu01
    楼上都告诉你了, memcpy(key,(unsigned char)"test",32); 这个会复制 32 个字节,但是 test 只有 5 个字节
    所以你这里应该 memcpy(key,(unsigned char)"test", strlen("test"));或者 memcpy(key,(unsigned char)"test", strlen("test")+1);
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    15
    @xujif 但是 aes 要求传入的必需是 32 个字节的,所以它用了 memset(buf,0,32);去初始化 32 字节内存,只要存进去的是 32 字节以下的,多出来的位数都会用'\0'补全,这个理论我也用调试印证了,多出来的部分确实是\0 补全的
    tghgffdgd
    tghgffdgd
    Jan 25, 2016
    16
    @wohenyingyu01 "test"补全的\0 只能保证一位,你复制 32 个进去, 5 个之后已经不一定是\0 了,谁告诉多出来的部分确实是\0 补全的。
    xujif
    xujif
    Jan 25, 2016
    17
    @wohenyingyu01 memcpy 会强制拷贝 32 个字节,在这里前面 memset 是多余的,调试模式很多编译器会对变量填 0,release 并不会。
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    18
    @tghgffdgd
    @xujif
    额,有道理,可能是这个造成的
    Echoldman
    Echoldman
    Jan 25, 2016
    19
    memcpy 的 size 是字节,楼主你的调用,是按照位来算的
    zzzaaasss
    zzzaaasss
    Jan 25, 2016 via Android
    20
    cbc 不是要初始化 iv 么? iv 是怎么来的
    skydiver
    skydiver
    Jan 25, 2016 via Android
    21
    为啥是 unsigned char 不应该是转换成 void *么,再不济也是 unsigned char*
    zonyitoo
    zonyitoo
    Jan 25, 2016
    22
    memcpy(key,(unsigned char)"test",32);

    看到这句笑翻了………
    除了上面说的越界之后,我还有个问题,为什么要强转类型为 unsigned char ?
    402124773
    402124773
    Jan 25, 2016
    23
    你把这个程序在同一个平台下连续运行两次,看看结果是否一致,不就可以得出“是否是因为 memcpy 长度太长导致后面的数据有问题”的结论了吗???
    auser
    auser
    Jan 25, 2016 via Android
    24
    楼上说的几处代码都是不好的,楼主还是改过来好了。

    以前用 C 实现过一整套的 aes_cbc.
    里边除了 block cipher modes 需要了解, padding 也要关注的。还有初始化向量 IV 这些细节。

    建议楼主搞清楚这些概念后选择个合适的库好了,不要直接从这些底层入手。
    hitmanx
    hitmanx
    Jan 25, 2016❤️1
    25
    没看明白.memset 和 memcpy 没关系,可以 memset 去清空 32 位为'\0',但是依然只去 memcpy 前几位,这样后面几位并不会受影响."test"作为 const char*,应该是存在全局变量的 read-only 段的,memcpy(,,32)会把这个段后面的数据一起去拷贝,结果是未定义的.另外这儿感觉用 strncpy 会比 memcpy 好一些.
    wadahana
    wadahana
    Jan 25, 2016
    26
    @402124773 有可能是一样的, 表忘了可能会有 “烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫”
    k9982874
    k9982874
    Jan 25, 2016
    27
    "不同语言的库加密出来的结果都不一样,也不能互相解密"

    只能说你的实现有问题,算法正确的话出来的值是可以用任何语言的实现解密的。

    "memcpy(key,(unsigned char)"test",32);"
    如果算法实现没问题,这句应该是罪魁祸首,原因前面的同学已经说了。

    最近刚实现了一套 C 的 AES ,产生的结果 PHP JAVA 都可以互解。
    jasontse
    jasontse
    Jan 25, 2016 via iPad
    28
    看标题就知道是未定义内存的坑
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    29
    @402124773 运行过是一样的额
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    30
    @k9982874 这个代码奇怪的地方在于,无论加密出来的结果有多不一样,只要在同一个环境下对结果去解密都能解出正确的来,如果把结果从外面传进来,就解不出……
    wizardoz
    wizardoz
    Jan 25, 2016
    31
    @wohenyingyu01 不仅仅是 32 字节和 5 字节的问题。你把指针强制转换成 unsigned char 了,少个星号!
    也就是说指针的值溢出后变成了一个 0-255 之间的值。
    wizardoz
    wizardoz
    Jan 25, 2016
    32
    @wizardoz 难道是语言特性?抱歉我以为是 C 语言,请忽略我。
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    33
    @wizardoz 火眼金睛!不过我看了下代码里面是有的,不知道为啥复制过来没了
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    34
    @skydiver 我看了下代码里面是有的,不知道为啥复制过来没了额
    waruqi
    waruqi
    Jan 25, 2016
    35
    这代码 也是醉了。。
    sophymax
    sophymax
    Jan 25, 2016
    36
    其实是还没完全理清那个加密算法 , 有些参数需要设置的 , 某个库默认设置的不一样 , salt 值 IV 值 之类的 , 还有可能是最后是不是多了一个字节的内存
    skydiver
    skydiver
    Jan 25, 2016
    37
    @wohenyingyu01 原来是变成 markdown 粗体了……
    wohenyingyu01
    wohenyingyu01
    OP
    Jan 25, 2016
    38
    @sophymax 那个 c 代码完全看不懂,理不清了,可能还需要从 aes 原理入手研究了,实在不行换一个方法,谢啦
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1636 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 63ms · UTC 13:13 · PVG 21:13 · LAX 05:13 · JFK 08:13
    ♥ Do have faith in what you're doing.