【RFC-1321】MD5信息摘要算法

1      概述


         本文描述了MD5信息摘要算法(MD5Message-digest Algorithm)。这个算法将一个任意长度的信息作为输入,并产出该信息的128位“信息指纹”或“信息摘要”。可以推断,两个不同的输入信息不会产生相同的MD5输出;根据指定的MD5,也难以产生与之对应的信息。MD5算法用于数字签名领域。这在此领域中,一个大的文件在被使用一个公钥系统(如RAS)的私有(或秘密)钥匙加密前,必须被以安全的方式进行“压缩”。

         MD5算法被设计用于较快速的32-bit机。此外,MD5算法不需要大的替换表;这个算法也能被简洁的编写。

         MD5算法是MD4信息摘要算法1,2]的扩展。MD5会比MD4稍慢一些,但是它在设计上更加“保守”。MD5被设计的原因是,一些现有批评认为MD4适用于于要求“快速”的应用中(因为MD4设计的初衷就是快速)但它处在被成功地加密攻击的边缘。MD5相比MD4的设计更加保守,放弃了一定的速度而去追求最终的目标——安全。它吸纳了许多评论者的建议,并且进行了一些优化。MD5算法现在公布,并公开寻求意见建议,它可能会被作为一个标准实施。

         对于基于OSI的应用来讲,MD5对象的标识符为

                  md5 OBJECTIDENTIFIER ::=

                           iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5}

         在 X.509 类算法标识符[3],MD5的参数应被标志为NULL。


2      术语及注意事项


         在文档中,一个“字(word)”是一个32位量,一个“字节(byte)”是一个8位量。一串比特(bit),可以用一种自然的方式解释为一串字节。即每连续的8位作为一组,按高位在前的方式转化为字节。类似的,一串字节可以被解释为一串32位字,即每4个字节为一组,以低位在前的方式转化为字。

         x_1 表示x数组中第i个元素。如果下标i是一个表达式,则对其加大括号,x_{i+1}。类似的,我们也是用指数上标,如x^i表示x的i次方。

         符号“+”表示两个字相加(2^32取模加法)。X <<<s表示32位字X向左循环移位s位。not(X)表示对X按位取反,X v Y表示对X、Y进行按位或操作。X xor Y表示对X、Y进行按位抑或操作,XY表示对XY进行按位与操作。


3      MD5算法描述


         假设我们有一个b位的信息作为输入,我们希望获取它的信息摘要。b是一个任意非负整数,即b可以是0,也无需是8的整数倍,它也可以任意大。我们将信息写作如下格式:

m_0m_1 ... m_{b-1}

         下面五步用于计算MD5信息摘要。


3.1  步骤1. 附加对齐位


         首先信息要被对齐(扩展),使它的长度(按位计算)除以512余448. 这样,信息再添加64位其长度就可以达到512的整数倍。对齐操作一定要执行,即使信息的长度已经满足除以512余448.

         对齐操作如下:一个单独的比特“1” 首先被附加在信息后,然后在后面再附加比特“0”,直到信息的长度满足除以512余448. 总之对其操作至少附加1位,至多附加512位。


3.2  步骤2. 附加长度


         一个64位的无符号整数b(原始信息在未添加附加位前的按位计算的长度)被附加在上一步对齐后的信息之后。通常,b不会大于2^64,只有64位的低字节被使用(这个64位量可被看作为两个32位字,并首先附加低阶的32位字,后附加高阶的,这与之前的定义一致)。

         此时,生成的信息(在对齐和附加b后)的长度已经是512位的整数倍。等价的,信息的长度也是16个32位字的整数倍。将这个生成的标记为M[0 … N-1],M是一个32位字的数组,N为16的整数倍。


3.3  步骤3. 初始化MD缓冲区


         一个4字长的缓冲区[A, B,C, D]被用于计算信息摘要。其中A、B、C、D都是32位寄存器。这些寄存器备用下面的值(十六进制表示)初始化,低阶字节放在最先。

                           字A: 01 23 4567

                           字 B: 89 ab cdef

                           字 C: fe dc ba98

                           字D: 76 54 32 10

         即:A =0x67452301, B = efcdab89, C = 0x98badcfe, D = 10325476.


3.4  步骤4. 按16字每块处理信息


         我们首先定义4个辅助函数,他们每个都将3个32位字作为输入,并产生一个32位字的输出。

                           F(X,Y,Z)    =       XY v not(X) Z

                           G(X,Y,Z)   =      XZ v Y not(Z)

                           H(X,Y,Z)   =      X xor Y xor Z

                           I(X,Y,Z)     =      Y xor (X v not(Z))

         在函数F中,每一位都执行如下操作:如果X则Y,否则Z(if x then y, else z)。函数F可用+(即按位或操作|)代替v. 因为XY和not(X)Z在同一位不可能同时为1. 有趣的是,如果X、Y和Z是独立、无偏的,那么函数值F(X, Y, Z)也是独立、无偏的。

         函数G、H和I与F类似,他们都是“按位平行”执行操作,他们的输出都来自于X、Y和Z。如果X、Y、Z是独立、无偏的,那么他们的输出结果同样是独立、无偏的。注意,函数H的对他的输入执行按位“异或(xor)”或“奇偶性(parity)”操作。

         这一步使用含有64个元素的表T[1 …64]。T使用正弦函数(sine)构造。设T[i]为表中第i个元素,它等价于4294967296乘abs(sin(i))的结果的整数部分,i的单位是弧度。这个元素表将附在附录之中。

         执行如下操作:                          

 

         /* 对每一个16字组成的块进行处理 */

         For i = 0 toN/16-1 do

 

                  /* 将第i块复制到x中. */

                  For j = 0 to 15 do

                           Set X[j] to M[i*16+j].

                  end /* 循环j结束 */

 

                  /* 将A、B、C、D对应保存为AA、BB、CC、DD */

                  AA = A

                  BB = B

                  CC = C

                  DD = D

 

                  /* 第1轮 */

                  /* 以 [abcd k si] 表示操作

                           a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */

                  /*依此做下列十六个操作。*/

                  [ABCD  0 7  1]  [DABC 1 12  2]  [CDAB 2 17  3]  [BCDA 3 22  4]

                  [ABCD  4 7  5]  [DABC 5 12  6]  [CDAB 6 17  7]  [BCDA 7 22  8]

                  [ABCD  8 7  9]  [DABC 9 12 10]  [CDAB 10 17 11]  [BCDA 11 22 12]

                  [ABCD12  7 13] [DABC 13 12 14]  [CDAB 14 1715]  [BCDA 15 22 16]

 

                  /* 第2轮 */

                  /*以 [abcd k s i] 表示操作

                           a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */

                  /*依此做下列十六个操作。 */

                  [ABCD  1  517]  [DABC  6  918]  [CDAB 11 14 19]  [BCDA 0 20 20]

                  [ABCD  5  521]  [DABC 10  9 22] [CDAB 15 14 23]  [BCDA  4 20 24]

                  [ABCD  9  525]  [DABC 14  9 26] [CDAB  3 14 27]  [BCDA 8 20 28]

                  [ABCD13  5 29] [DABC  2  9 30] [CDAB  7 14 31]  [BCDA 12 20 32]

 

                  /*第3轮 */

                  /*以 [abcd k s t] 表示操作

                            a= b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */

                  /*依此做下列十六个操作。 */

                  [ABCD  5  433]  [DABC  8 11 34] [CDAB 11 16 35]  [BCDA 14 23 36]

                  [ABCD  1  437]  [DABC  4 11 38] [CDAB  7 16 39]  [BCDA 10 23 40]

                  [ABCD13  4 41] [DABC  0 11 42]  [CDAB 3 16 43]  [BCDA  6 23 44]

                  [ABCD  9  445]  [DABC 12 11 46]  [CDAB 15 16 47]  [BCDA 2 23 48]

 

                  /*第4轮 */

                  /*以 [abcd k s t] 表示操作

                            a= b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */

                  /*依此做下列十六个操作。*/

                  [ABCD  0  649]  [DABC  7 10 50] [CDAB 14 15 51]  [BCDA  5 21 52]

                  [ABCD12  6 53] [DABC  3 10 54]  [CDAB 10 15 55]  [BCDA 1 21 56]

                  [ABCD  8  657]  [DABC 15 10 58]  [CDAB 6 15 59]  [BCDA 13 21 60]

                  [ABCD  4  661]  [DABC 11 10 62]  [CDAB 2 15 63]  [BCDA  9 21 64]

          

                  /*执行下列加法,即每个寄存器加在4轮操作开始前的值。*/

                  A= A + AA

                  B= B + BB

                  C= C + CC

                  D= D + DD

 

         end /* 循环i结束*/


3.5  输出


         信息摘要的输出为A、B、C、D. 我们从A的低阶字节开始输出,到D的高阶字节结束。

 

         MD5算法描述至此完成。一个可供参考的C语言实现会在附录中给出。


4      总结


         MD5信息摘要算法是一个易于实现的算法,它提供了任意长度的信息的“信息指纹”或信息摘要。可以推断出,很难找到两个信息具有相同的信息摘要,因为这将进行2^64次操作;而根据给出的MD5码寻找具有这样信息摘要的原信息则需要2^128操作。MD5算法已经经过了详细的脆弱性检测。当然,新的算法和未来的安全分析技术无疑是合理的,正如新的建议一样。


附录:


A. MD5.h
/*
 * Copy right: HolyChen.
 * Create Time: 2014.
 * Lisence: MIT/X.
  * Reference: RFC 1321 http://www.rfc-editor.org/rfc/rfc1321.txt
 */
#ifndef _MD5_H_
#define _MD5_H_


/*
* ------------------- NOCATION! -------------------
* ALL char, long used to calculate MD5, must be unsigned!.
* ------------------- NOCATION! -------------------
*/




/*
 * Define the four words used to compute the message digets.
 */
#define WORD_A 0x67452301
#define WORD_B 0xEFCDAB89
#define WORD_C 0x98BADCFE
#define WORD_D 0x10325476


// Round constant
#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21


const unsigned char PADDINGS[64] = {
    (unsigned char)0x80
};


/*
* Define the four auxiliary function the each take as input
* three 32-bit words and prodcue as output one 32-bit word.
*/
inline unsigned long functionF(unsigned long x, unsigned long y, unsigned long z);
inline unsigned long functionG(unsigned long x, unsigned long y, unsigned long z);
inline unsigned long functionH(unsigned long x, unsigned long y, unsigned long z);
inline unsigned long functionI(unsigned long x, unsigned long y, unsigned long z);
inline unsigned long roundLeft(unsigned long x, unsigned long n);
inline void round1(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, short xk, unsigned long s, unsigned long ti);
inline void round2(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, short xk, unsigned long s, unsigned long ti);
inline void round3(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, short xk, unsigned long s, unsigned long ti);
inline void round4(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, short xk, unsigned long s, unsigned long ti);


/*
* Get MD5 code in ASCII represent.
*/
char* getMD5inASCII(unsigned long state[4]);


/*
* The message is "padded" (extended) so that its length (in bits) is
* congruent to 448, modulo 512. That is, the message is extended so
* that it is just 64 bits shy of being a multiple of 512 bits long.
* Padding is always performed, even if the length of the message is
* already congruent to 448, modulo 512.
*
* Padding is performed as follows: a single "1" bit is appended to the
* message, and then "0" bits are appended so that the length in bits of
* the padded message becomes congruent to 448, modulo 512. In all, at
* least one bit and at most 512 bits are appended.
*/
unsigned char* paddingClearText(unsigned char* clearText, unsigned long long originLength, unsigned long long *newLength);


/*
* A 64-bit representation of b (the length of the message before the
* padding bits were added) is appended to the result of the previous
* step. In the unlikely event that b is greater than 2^64, then only
* the low-order 64 bits of b are used. (These bits are appended as two
* 32-bit words and appended low-order word first in accordance with the
* previous conventions.)
*/
unsigned char* appendBitLength(unsigned char* paddedData, unsigned long long offset, unsigned long long bitLength,
    unsigned long long *totalLength);


/*
* Core algorithm of calculate md5.
*/
void md5Core(unsigned char *paddedData, unsigned long* state);


#endif

B. MD5.cpp
/*
* Copy right: HolyChen.
* Create Time: 2014.
* Lisence: MIT/X.
* Reference: RFC 1321 http://www.rfc-editor.org/rfc/rfc1321.txt
*/
#include "MD5.h"
#include <string.h>
#include <stdlib.h>


/*
 * ------------------- NOCATION! -------------------
 * ALL char, long used to calculate MD5, must be unsigned!.
 * ------------------- NOCATION! -------------------
 */




/*
 * Define the four auxiliary function the each take as input
 * three 32-bit words and prodcue as output one 32-bit word.
 */
inline unsigned long functionF(unsigned long x, unsigned long y, unsigned long z) {
    return (x & y) | (~x & z);
}


inline unsigned long functionG(unsigned long x, unsigned long y, unsigned long z) {
    return (x & z) | (y & ~z);
}


inline unsigned long functionH(unsigned long x, unsigned long y, unsigned long z) {
    return x ^ y ^ z;
}


inline unsigned long functionI(unsigned long x, unsigned long y, unsigned long z) {
    return y ^ (x | ~z);
}


/*
 * Define round left function in int_32.
 */
inline unsigned long roundLeft(unsigned long x, unsigned long n) {
    return (x << n) | (x >> (32 - n));
}


/*
 * Define four round function.
 */
inline void round1(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, unsigned long xk, unsigned long s, unsigned long ti) {
    *a = b + roundLeft((*a + functionF(b, c, d) + xk + ti), s);
}
    
inline void round2(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, unsigned long xk, unsigned long s, unsigned long ti) {
    *a = b + roundLeft((*a + functionG(b, c, d) + xk + ti), s);
}


inline void round3(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, unsigned long xk, unsigned long s, unsigned long ti) {
    *a = b + roundLeft((*a + functionH(b, c, d) + xk + ti), s);
}


inline void round4(unsigned long *a, unsigned long b, unsigned long c, unsigned long d, unsigned long xk, unsigned long s, unsigned long ti) {
    *a = b + roundLeft((*a + functionI(b, c, d) + xk + ti), s);
}


/*
 * Get MD5 code in ASCII represent.
 */
char* getMD5inASCII(unsigned long state[4]) {
    
    unsigned char temp[16];
    for (int i = 0; i < 4; i++) {
        memcpy(temp + i * 4, (unsigned char*)(state + i), 4);
    }
    char* ascii = new char[33];
    for (int i = 0; i < 16; i++) {
        // 2 unsigned char width
        if ((temp[i] & 0xF0) != 0) {
            _ltoa(temp[i] & 0xff, ascii + i * 2, 16);
        } else {
            ascii[i * 2] = '0';
            _ltoa(temp[i] & 0xff, ascii + i * 2 + 1, 16);
        }
    }
    ascii[32] = 0;
    return ascii;
}


/*
 * The message is "padded" (extended) so that its length (in bits) is
 * congruent to 448, modulo 512. That is, the message is extended so
 * that it is just 64 bits shy of being a multiple of 512 bits long.
 * Padding is always performed, even if the length of the message is
 * already congruent to 448, modulo 512.
 *
 * Padding is performed as follows: a single "1" bit is appended to the
 * message, and then "0" bits are appended so that the length in bits of
 * the padded message becomes congruent to 448, modulo 512. In all, at
 * least one bit and at most 512 bits are appended.
 *
 * @param clearText Data to padding 100000...b.
 * @param originLength Length of clearText, it's unit is byte.
 * @param *newLength the length of clearText after padding.
 *
 * @return clearText after padding, and 64-bits blank at the end need appending.
 */
unsigned char* paddingClearText(unsigned char* clearText, unsigned long long originLength, unsigned long long *newLength) {
    // get the length need to padding, so (clearText.len - 56) % 64 == 0.
    unsigned long long paddingLength = 64LL - (originLength + 8LL) % 64LL;


    // padding
    unsigned char* paddedData = new unsigned char[originLength + paddingLength + 8];
    memcpy(paddedData, clearText, originLength);
    memcpy(paddedData + originLength, PADDINGS, paddingLength);
    *newLength = originLength + paddingLength;
    return paddedData;
}


/*
 * A 64-bit representation of b (the length of the message before the
 * padding bits were added) is appended to the result of the previous
 * step. In the unlikely event that b is greater than 2^64, then only
 * the low-order 64 bits of b are used. (These bits are appended as two
 * 32-bit words and appended low-order word first in accordance with the
 * previous conventions.)
 *
 * @param paddedData the data after paddingClearText.
 * @param offset the length of paddedData without 64-bits blank, it's unit is byte.
 * @param bitLength the length of source data in BITS, it possible differs from
 *            length of paddedData before padded, because the message could
 *            be parited.
 *
 * @return paddedData appended by bitLength, so the newLength you can get by offset + 8.
 */
unsigned char* appendBitLength(unsigned char* paddedData, unsigned long long offset, unsigned long long bitLength,
    unsigned long long *totalLength) {
    memcpy(paddedData + offset, (unsigned char*)&bitLength, 8);
    *totalLength = offset + 8;
    return paddedData;
}


unsigned long x[16];


/*
 * Core algorithm of calculate md5, you can understand it by reading RFC 1321,
 * however, I suggest you shouldn't do that, you can't understand, because the
 * document say nothing.
 *
 * @param paddedData the clearData after padding 1000....b and length in bit,
 *           so, the length of it in byte should divisible by 8.
 * @param state state of register a, b, c and d in order.
 */
void md5Core(unsigned char *paddedData, unsigned long* state) {
    unsigned long AA = state[0], BB = state[1], CC = state[2], DD = state[3];


    // Save word to X
    for (int j = 0; j < 16; j++) {
        x[j] = *(unsigned long*)(paddedData + j * 4);
    }


    /* Round 1 */
    round1(&state[0], state[1], state[2], state[3], x[0], S11, 0xd76aa478); /* 1 */
    round1(&state[3], state[0], state[1], state[2], x[1], S12, 0xe8c7b756); /* 2 */
    round1(&state[2], state[3], state[0], state[1], x[2], S13, 0x242070db); /* 3 */
    round1(&state[1], state[2], state[3], state[0], x[3], S14, 0xc1bdceee); /* 4 */
    round1(&state[0], state[1], state[2], state[3], x[4], S11, 0xf57c0faf); /* 5 */
    round1(&state[3], state[0], state[1], state[2], x[5], S12, 0x4787c62a); /* 6 */
    round1(&state[2], state[3], state[0], state[1], x[6], S13, 0xa8304613); /* 7 */
    round1(&state[1], state[2], state[3], state[0], x[7], S14, 0xfd469501); /* 8 */
    round1(&state[0], state[1], state[2], state[3], x[8], S11, 0x698098d8); /* 9 */
    round1(&state[3], state[0], state[1], state[2], x[9], S12, 0x8b44f7af); /* 10 */
    round1(&state[2], state[3], state[0], state[1], x[10], S13, 0xffff5bb1); /* 11 */
    round1(&state[1], state[2], state[3], state[0], x[11], S14, 0x895cd7be); /* 12 */
    round1(&state[0], state[1], state[2], state[3], x[12], S11, 0x6b901122); /* 13 */
    round1(&state[3], state[0], state[1], state[2], x[13], S12, 0xfd987193); /* 14 */
    round1(&state[2], state[3], state[0], state[1], x[14], S13, 0xa679438e); /* 15 */
    round1(&state[1], state[2], state[3], state[0], x[15], S14, 0x49b40821); /* 16 */
    /* Round 2 */
    round2(&state[0], state[1], state[2], state[3], x[1], S21, 0xf61e2562); /* 17 */
    round2(&state[3], state[0], state[1], state[2], x[6], S22, 0xc040b340); /* 18 */
    round2(&state[2], state[3], state[0], state[1], x[11], S23, 0x265e5a51); /* 19 */
    round2(&state[1], state[2], state[3], state[0], x[0], S24, 0xe9b6c7aa); /* 20 */
    round2(&state[0], state[1], state[2], state[3], x[5], S21, 0xd62f105d); /* 21 */
    round2(&state[3], state[0], state[1], state[2], x[10], S22, 0x2441453); /* 22 */
    round2(&state[2], state[3], state[0], state[1], x[15], S23, 0xd8a1e681); /* 23 */
    round2(&state[1], state[2], state[3], state[0], x[4], S24, 0xe7d3fbc8); /* 24 */
    round2(&state[0], state[1], state[2], state[3], x[9], S21, 0x21e1cde6); /* 25 */
    round2(&state[3], state[0], state[1], state[2], x[14], S22, 0xc33707d6); /* 26 */
    round2(&state[2], state[3], state[0], state[1], x[3], S23, 0xf4d50d87); /* 27 */
    round2(&state[1], state[2], state[3], state[0], x[8], S24, 0x455a14ed); /* 28 */
    round2(&state[0], state[1], state[2], state[3], x[13], S21, 0xa9e3e905); /* 29 */
    round2(&state[3], state[0], state[1], state[2], x[2], S22, 0xfcefa3f8); /* 30 */
    round2(&state[2], state[3], state[0], state[1], x[7], S23, 0x676f02d9); /* 31 */
    round2(&state[1], state[2], state[3], state[0], x[12], S24, 0x8d2a4c8a); /* 32 */
    /* Round 3 */
    round3(&state[0], state[1], state[2], state[3], x[5], S31, 0xfffa3942); /* 33 */
    round3(&state[3], state[0], state[1], state[2], x[8], S32, 0x8771f681); /* 34 */
    round3(&state[2], state[3], state[0], state[1], x[11], S33, 0x6d9d6122); /* 35 */
    round3(&state[1], state[2], state[3], state[0], x[14], S34, 0xfde5380c); /* 36 */
    round3(&state[0], state[1], state[2], state[3], x[1], S31, 0xa4beea44); /* 37 */
    round3(&state[3], state[0], state[1], state[2], x[4], S32, 0x4bdecfa9); /* 38 */
    round3(&state[2], state[3], state[0], state[1], x[7], S33, 0xf6bb4b60); /* 39 */
    round3(&state[1], state[2], state[3], state[0], x[10], S34, 0xbebfbc70); /* 40 */
    round3(&state[0], state[1], state[2], state[3], x[13], S31, 0x289b7ec6); /* 41 */
    round3(&state[3], state[0], state[1], state[2], x[0], S32, 0xeaa127fa); /* 42 */
    round3(&state[2], state[3], state[0], state[1], x[3], S33, 0xd4ef3085); /* 43 */
    round3(&state[1], state[2], state[3], state[0], x[6], S34, 0x4881d05); /* 44 */
    round3(&state[0], state[1], state[2], state[3], x[9], S31, 0xd9d4d039); /* 45 */
    round3(&state[3], state[0], state[1], state[2], x[12], S32, 0xe6db99e5); /* 46 */
    round3(&state[2], state[3], state[0], state[1], x[15], S33, 0x1fa27cf8); /* 47 */
    round3(&state[1], state[2], state[3], state[0], x[2], S34, 0xc4ac5665); /* 48 */
    /* Round 4 */
    round4(&state[0], state[1], state[2], state[3], x[0], S41, 0xf4292244); /* 49 */
    round4(&state[3], state[0], state[1], state[2], x[7], S42, 0x432aff97); /* 50 */
    round4(&state[2], state[3], state[0], state[1], x[14], S43, 0xab9423a7); /* 51 */
    round4(&state[1], state[2], state[3], state[0], x[5], S44, 0xfc93a039); /* 52 */
    round4(&state[0], state[1], state[2], state[3], x[12], S41, 0x655b59c3); /* 53 */
    round4(&state[3], state[0], state[1], state[2], x[3], S42, 0x8f0ccc92); /* 54 */
    round4(&state[2], state[3], state[0], state[1], x[10], S43, 0xffeff47d); /* 55 */
    round4(&state[1], state[2], state[3], state[0], x[1], S44, 0x85845dd1); /* 56 */
    round4(&state[0], state[1], state[2], state[3], x[8], S41, 0x6fa87e4f); /* 57 */
    round4(&state[3], state[0], state[1], state[2], x[15], S42, 0xfe2ce6e0); /* 58 */
    round4(&state[2], state[3], state[0], state[1], x[6], S43, 0xa3014314); /* 59 */
    round4(&state[1], state[2], state[3], state[0], x[13], S44, 0x4e0811a1); /* 60 */
    round4(&state[0], state[1], state[2], state[3], x[4], S41, 0xf7537e82); /* 61 */
    round4(&state[3], state[0], state[1], state[2], x[11], S42, 0xbd3af235); /* 62 */
    round4(&state[2], state[3], state[0], state[1], x[2], S43, 0x2ad7d2bb); /* 63 */
    round4(&state[1], state[2], state[3], state[0], x[9], S44, 0xeb86d391); /* 64 */


    state[0] += AA;
    state[1] += BB;
    state[2] += CC;
    state[3] += DD;
}



C. 用于测试的main.cpp  
/*
* Copy right: HolyChen.
* Create Time: 2014.
* Lisence: MIT/X.
* Reference: RFC 1321 http://www.rfc-editor.org/rfc/rfc1321.txt
*/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "md5.h"


/*
* ------------------- NOCATION! -------------------
* ALL char, long used to calculate MD5, must be unsigned!.
* ------------------- NOCATION! -------------------
*/




void UNIT_TEST(int order, char* src, char* expectMD5);


/*
* Calculate 32-bit MD5 code of clear text.
* @param clearText data need encrypting
* @param originLength length of clear text.
* @return a unsigned char array in heap, which represents md5 code of clearText in ASCII encoding.
*/
char* calculateMD5(unsigned char* clearText, unsigned long long originLength);




int main(int argc, char *argv[]) {
    UNIT_TEST(1, "", "d41d8cd98f00b204e9800998ecf8427e");
    UNIT_TEST(2, "a", "0cc175b9c0f1b6a831c399e269772661");
    UNIT_TEST(3, "abc", "900150983cd24fb0d6963f7d28e17f72");
    UNIT_TEST(4, "message digest", "f96b697d7cb7938d525a2f31aaf161d0");
    UNIT_TEST(5, "abcdefghijklmnopqrstuvwxyz", "c3fcd3d76192e4007dfb496cca67e13b");
    return 0;
}


void UNIT_TEST(int order, char* src, char* expectMD5) {
    char *md5;
    md5 = calculateMD5((unsigned char*)src, strlen(src));
    printf("Test Case %d\n", order);
    printf("************************ Start ************************\n");
    printf("String: %s\n", src);
    printf("\t       MD5: %s\n", md5);
    printf("\tExpect MD5: %s\n", expectMD5);
    printf("They are same: %s\n", strcmp(md5, expectMD5) == 0? "True" : "FALSE");
    printf("************************* End *************************\n");
    printf("\n\n\n");
    delete[] md5;
}


/*
* Calculate 32-bit MD5 code of clear text, you can write a script by simulate it.
* @param clearText data need encrypting
* @param originLength length of clear text.
* @return a unsigned char array in heap, which represents md5 code of clearText in ASCII encoding.
*/
char* calculateMD5(unsigned char* clearText, unsigned long long originLength) {
    unsigned char *paddedData;
    // padding the clear text
    unsigned long long paddedLength;
    paddedData = paddingClearText(clearText, originLength, &paddedLength);


    // Append origin information data length in bit.
    unsigned long long originBitLength = originLength * 8;
    unsigned long long totalLength;
    // append length of clearText in bit.
    paddedData = appendBitLength(paddedData, paddedLength, originBitLength, &totalLength);


    // The data would be used 4 byte a time, means a 32-bits word.
    unsigned long long newWordLength = totalLength / 4;


    unsigned long *state = new unsigned long[4] {
        WORD_A, WORD_B, WORD_C, WORD_D
    };
    // Process 16 word per block
    for (unsigned long i = 0; i < newWordLength / 16; i++) {
        md5Core(paddedData + i * 16 * 4, state);
    }
    delete[] paddedData;
    // To use easy, return a ascii represent to print directly.
    char* asciiRepre = getMD5inASCII(state);
    delete[] state;
    return asciiRepre;
}


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值