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算法已经经过了详细的脆弱性检测。当然,新的算法和未来的安全分析技术无疑是合理的,正如新的建议一样。
附录:
/*
* 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;
}
/*
* 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;
}