zoukankan      html  css  js  c++  java
  • as3corelib 的 MD5.digest.endian 应该是 LITTLE_ENDIAN

    赖勇浩(http://laiyonghao.com

    MD5.digest 简介

    MD5 算法(http://en.wikipedia.org/wiki/MD5)已经是使用最为广泛的信息摘要算法之一,常用以错误检查,比如命令 md5sum。
    $ md5sum protobuf-2.4.1.tar.gz
    dc84e9912ea768baa1976cb7bbcea7b5  protobuf-2.4.1.tar.gz
    当我们通过网络传输 protobuf-2.4.1.tar.gz 后,可以在另一端通过比对它的 md5sum 结果是否相同来进行校验。
    如上我们可以看到 md5sum 的结果是 32 个字符的字符串,每个字符是一个 16 进制数,一般称之为 hexdigest。除了这种形式,md5 值还可以使用 16 字节的二进制序列来表示,称之为 digest。显然后者在空间上更有优势,所以有时候存储、网络传输 md5 值的时候,我们会选择使用 digest。
    根据 MD5 算法的 RFC(http://tools.ietf.org/html/rfc1321),我们可以知道其实 digest 就是 4 个连续存储的 4 字节的整型。我们也知道不同的平台上,有不同的字节序(http://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F),所以 RFC1321 在它的“APPENDIX A - Reference Implementation”里编写了 Encode/Decode 函数,指明 md5.digest 应该使用 LITTLE_ENDIAN。
    /* Encodes input (UINT4) into output (unsigned char). Assumes len is
      a multiple of 4.
     */
    static void Encode (output, input, len)
    unsigned char *output;
    UINT4 *input;
    unsigned int len;
    {
      unsigned int i, j;
    
      for (i = 0, j = 0; j < len; i++, j += 4) {
     output[j] = (unsigned char)(input[i] & 0xff);
     output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
     output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
     output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
      }
    }
    
    /* Decodes input (unsigned char) into output (UINT4). Assumes len is
      a multiple of 4.
     */
    static void Decode (output, input, len)
    UINT4 *output;
    unsigned char *input;
    unsigned int len;
    {
      unsigned int i, j;
    
      for (i = 0, j = 0; j < len; i++, j += 4)
     output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
       (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
    }
    而上文提到的 md5 wikipedia 页面也有一行代码注释提到应为小端序:
    var char digest[16] := h0 append h1 append h2 append h3 //(expressed as little-endian)

    as3corelib 的问题

    在 as3corelib 中,MD5.digest 是一个 ByteArray 实例,见 https://github.com/mikechambers/as3corelib/blob/master/src/com/adobe/crypto/MD5.as#L42 。ByteArray 实现了 IDataInput 和 IDataOutput 接口,自然也像其它实现了这两个接口的 FileStream, Socket 类一样继承了 endian 属性,其默认值是 BIG_ENDIAN。在 as3corelib 的当前实现中,digest 使用的是默认的 BIG_ENDIAN,见 https://github.com/mikechambers/as3corelib/blob/master/src/com/adobe/crypto/MD5.as#L182,或如下代码:
    digest = new ByteArray()
    digest.writeInt(a);
    digest.writeInt(b);
    digest.writeInt(c);
    digest.writeInt(d);
    digest.position = 0;
    当传输 digest 到另一个进程进行比对时,就会发现 md5 检验和不匹配的情况了。

    解决方案

    最根本的方案应该是给 as3corelib 打个 patch,修正这个 bug,使之实现符合 RFC,附 patch 如下:
    ---
     src/com/adobe/crypto/MD5.as |    4 +++-
     1 files changed, 3 insertions(+), 1 deletions(-)
    
    diff --git a/src/com/adobe/crypto/MD5.as b/src/com/adobe/crypto/MD5.as
    index da533cc..db5406a 100644
    --- a/src/com/adobe/crypto/MD5.as
    +++ b/src/com/adobe/crypto/MD5.as
    @@ -34,6 +34,7 @@ package com.adobe.crypto {
    
            import com.adobe.utils.IntUtil;
            import flash.utils.ByteArray;
    +       import flash.utils.Endian;
            /**
             * The MD5 Message-Digest Algorithm
             *
    @@ -178,7 +179,8 @@ package com.adobe.crypto {
                                    c += cc;
                                    d += dd;
                            }
    -                       digest = new ByteArray()
    +                       digest = new ByteArray();
    +                       digest.endian = Endian.LITTLE_ENDIAN;
                            digest.writeInt(a);
                            digest.writeInt(b);
                            digest.writeInt(c);
    -- 
    1.7.0.4
    我已经向 as3corelib 的维护者反映这个问题,估计不日就可以由官方修复。但在官方发布新版本之前,我们也可以选择两个变通方案,一是使用 hexdigest,二是编写一个自己的转换函数 toLittleEndianMd5Digest,把 MD5.digest 转为 LITTLE_ENDIAN,实现如下:
                function toLittleEndianMd5Digest(ba:ByteArray):ByteArray
                {
                    if(ba.endian == Endian.LITTLE_ENDIAN)
                    {
                        return ba;
                    }
                    var new_ba:ByteArray = new ByteArray();
                    new_ba.endian = Endian.LITTLE_ENDIAN;
                    new_ba.writeInt(ba.readInt());
                    new_ba.writeInt(ba.readInt());
                    new_ba.writeInt(ba.readInt());
                    new_ba.writeInt(ba.readInt());
                    new_ba.position = 0;
                    return new_ba;
                }
    ... // 省略业务代码
    // 在用到 MD5.digest 的地方
    var md5:ByteArray = toLittleEndianMd5Digest(MD5.digest);
    这个 toLittleEndianMd5Digest 函数能够在 as3corelib 修正这个 bug 以后保持兼容,所以不用担心后遗症,可以放心大胆地使用。

  • 相关阅读:
    nepenthes用法
    honeydctl命令
    honeyd路由拓扑
    Linux Samba服务器的安装
    honeyd使用
    FreeRTOS 事件标志组
    epoll函数
    Java程序:从命令行接收多个数字,求和并输出结果
    《大道至简》第一章读后感
    【诗词歌赋】 杂感- 贺小妹
  • 原文地址:https://www.cnblogs.com/aiwz/p/6154328.html
Copyright © 2011-2022 走看看