Lai Yonghao (http://laiyonghao.com)
Md5.digest Introduction
MD5 Algorithm (http://en.wikipedia.org/wiki/MD5) has been one of the most widely used information digest algorithm, commonly used to check errors, such as the command md5sum.
$ md5sum protobuf-2.4.1.tar.gzdc84e9912ea768baa1976cb7bbcea7b5 protobuf-2.4.1.tar.gz
When we transfer the protobuf-2.4.1.tar.gz over the network, we can verify it at the other end by comparing its md5sum results to be the same.
As shown above, we can see that the md5sum result is a 32 character string, each character is a hexadecimal number, which is generally called hexdigest. In addition to this form, the MD5 value can also be expressed using a 16-byte binary sequence, which is called digest. Obviously, the latter has more advantages in space, so sometimes digest is used when the MD5 value is stored and transmitted over the network.
According to the RFC (http://tools.ietf.org/html/rfc1321) of the MD5 algorithm, we can know that digest is 4 consecutive 4-byte integer. We also know that there are different byte order (http://zh.wikipedia.org/wiki/%E5%AD%97%E8%8A%82%E5%BA%8F) on different platforms, so rfc1321 wrote the encode/decode function in its "Appendix A-reference implementation, specify that md5.digest should use 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);}
The MD5 Wikipedia page mentioned above also has a line of code comment that should be in the small-end order:
var char digest[16] := h0 append h1 append h2 append h3 //(expressed as little-endian)
As3corelib Problems
In as3corelib, md5.digest is a bytearray instance, see https://github.com/mikechambers/as3corelib/blob/master/src/com/adobe/crypto/MD5.as#L42. Bytearray implements the idatainput and idataoutput interfaces. Naturally, like other filestreams that implement these two interfaces, the socket class inherits the endian attribute. The default value is big_endian. In the current implementation of as3corelib, digest uses the default big_endian. For details, see:
digest = new ByteArray()digest.writeInt(a);digest.writeInt(b);digest.writeInt(c);digest.writeInt(d);digest.position = 0;
When digest is transmitted to another process for comparison, MD5 verification and mismatch will be found.
Solution
The most fundamental solution should be to install a patch for as3corelib to correct the bug and make it conform to the RFC. the patch is attached as follows:
--- 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.asindex 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
I have reported this problem to as3corelib maintainers. It is estimated that the problem will be solved by the official website in a few days. However, before the official release of the new version, we can also select two solutions: Use hexdigest, compile a conversion function tolittleendianmd5digest, and convert md5.digest to little_endian. The implementation is as follows:
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 ;}... // omitting the Business Code // var MD5: bytearray = tolittleendianmd5digest (md5.digest) Where md5.digest is used );
This tolittleendianmd5digest function can be compatible after as3corelib fixes this bug, so you don't have to worry about the sequelae and can use it with confidence.