MD5 算法
假设我们有 b - bits 的数据,需要计算他的电子签名 , 对于任意的 b ( 甚至可以是 0 , 但是必须是 8 的倍数) 。
追加对齐bit数据。
让数据对齐成 模512 byte 剩余448 byte 的长度。 追加数据一定要进行,哪怕数据本来就是模512 byte 剩余448 byte, 也得追加512个byte来对对齐。 追加数据的方式是第一个bit是1 。 其余的bit全部是 0 。
追加长度
对于追加了对齐数据后的数据,将原始数据的长度 ( in bits)( 64 bit 数据表示, 小32位在前 )追加到数据后面。这样最终得到512 byte 的倍数的数据。
初始化 4 byte 长度的电子签名
先低 byte :
word A: 01 23 45 67
word B: 89 ab cd ef
word C: fe dc ba 98
word D: 76 54 32 10
每 16 bytes 走下面的流程 :
。。。 各种扭曲平移。。。
将ABCD一次从小的byte 到大依次输出为MD5电子签名
代码
#include <math.h>
#include <string.h>
#include "md5.h"
static const MD5_word A_init = 0x67452301;
static const MD5_word B_init = 0xefcdab89;
static const MD5_word C_init = 0x98badcfe;
static const MD5_word D_init = 0x10325476;
static const MD5_word T[65] = {
/* 4294967296 * abs( sin ( i ) ) */
0 ,
3614090360, 3905402710, 606105819, 3250441966,
4118548399, 1200080426, 2821735955, 4249261313,
1770035416, 2336552879, 4294925233, 2304563134,
1804603682, 4254626195, 2792965006, 1236535329,
4129170786, 3225465664, 643717713, 3921069994,
3593408605, 38016083, 3634488961, 3889429448,
568446438, 3275163606, 4107603335, 1163531501,
2850285829, 4243563512, 1735328473, 2368359562,
4294588738, 2272392833, 1839030562, 4259657740,
2763975236, 1272893353, 4139469664, 3200236656,
681279174, 3936430074, 3572445317, 76029189,
3654602809, 3873151461, 530742520, 3299628645,
4096336452, 1126891415, 2878612391, 4237533241,
1700485571, 2399980690, 4293915773, 2240044497,
1873313359, 4264355552, 2734768916, 1309151649,
4149444226, 3174756917, 718787259, 3951481745 };
// XY ==> X&Y
// not (X) ==> ~X
// X v Y ==> X | Y
// X xor Y ==> X ^ Y
// X <<< s ==> ( X << s ) | ( X >> (32 -s ) )
//F(X,Y,Z) = XY v not(X) Z
inline MD5_word F(MD5_word X , MD5_word Y , MD5_word Z) {
return X & Y | ~X & Z ;
}
//G(X,Y,Z) = XZ v Y not(Z)
inline MD5_word G(MD5_word X , MD5_word Y , MD5_word Z) {
return X & Z ^ Y & ~Z ;
}
//H(X,Y,Z) = X xor Y xor Z
inline MD5_word H(MD5_word X , MD5_word Y , MD5_word Z) {
return X ^ Y ^ Z ;
}
//I(X,Y,Z) = Y xor (X v not(Z))
inline MD5_word I(MD5_word X , MD5_word Y , MD5_word Z) {
return Y ^ ( X | ~ Z ) ;
}
/* Round 1. */
/* Let [abcd k s i] denote the operation
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
#define ROUND1(a,b,c,d,k,s,i) \
a = a + F(b,c,d) + X[k] + T[i] ; \
a = ( a << s | a>>(32 - s) ) + b;
/* Round 2. */
/* Let [abcd k s i] denote the operation
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
#define ROUND2(a,b,c,d,k,s,i) \
a = a + G(b,c,d) + X[k] + T[i] ; \
a = ( a << s | a>>(32 - s) ) + b;
/* Round 3. */
/* Let [abcd k s t] denote the operation
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
#define ROUND3(a,b,c,d,k,s,i) \
a = a + H(b,c,d) + X[k] + T[i] ; \
a = ( a << s | a>>(32 - s) ) + b;
/* Round 4. */
/* Let [abcd k s t] denote the operation
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
#define ROUND4(a,b,c,d,k,s,i) \
a = a + I(b,c,d) + X[k] + T[i] ; \
a = ( a << s | a>>(32 - s) ) + b;
void MD5_16Word(const MD5_word X[16] ,struct MD5Content * content) {
register MD5_word AA = content->A;
register MD5_word BB = content->B;
register MD5_word CC = content->C;
register MD5_word DD = content->D;
ROUND1(AA, BB, CC, DD, 0, 7, 1)
ROUND1(DD, AA, BB, CC, 1, 12, 2)
ROUND1(CC, DD, AA, BB, 2, 17, 3)
ROUND1(BB, CC, DD, AA, 3, 22, 4)
ROUND1(AA,BB,CC,DD, 4 , 7, 5 );
ROUND1(DD,AA,BB,CC, 5 , 12, 6);
ROUND1(CC,DD,AA,BB, 6 , 17, 7);
ROUND1(BB,CC,DD,AA, 7 , 22, 8);
ROUND1(AA,BB,CC,DD, 8 , 7, 9 );
ROUND1(DD,AA,BB,CC, 9 , 12, 10);
ROUND1(CC,DD,AA,BB, 10 , 17, 11);
ROUND1(BB,CC,DD,AA, 11 , 22, 12);
ROUND1(AA,BB,CC,DD, 12 , 7, 13 );
ROUND1(DD,AA,BB,CC, 13 , 12, 14);
ROUND1(CC,DD,AA,BB, 14 , 17, 15);
ROUND1(BB,CC,DD,AA, 15 , 22, 16);
ROUND2(AA,BB,CC,DD, 1 , 5, 17 );
ROUND2(DD,AA,BB,CC, 6 , 9, 18);
ROUND2(CC,DD,AA,BB, 11 , 14, 19);
ROUND2(BB,CC,DD,AA, 0 , 20, 20);
ROUND2(AA,BB,CC,DD, 5 , 5, 21 );
ROUND2(DD,AA,BB,CC, 10 , 9, 22);
ROUND2(CC,DD,AA,BB, 15 , 14, 23);
ROUND2(BB,CC,DD,AA, 4 , 20, 24);
ROUND2(AA,BB,CC,DD, 9 , 5, 25 );
ROUND2(DD,AA,BB,CC, 14 , 9, 26);
ROUND2(CC,DD,AA,BB, 3 , 14, 27);
ROUND2(BB,CC,DD,AA, 8 , 20, 28);
ROUND2(AA,BB,CC,DD, 13 , 5, 29 );
ROUND2(DD,AA,BB,CC, 2 , 9, 30);
ROUND2(CC,DD,AA,BB, 7 , 14, 31);
ROUND2(BB,CC,DD,AA, 12 , 20, 32);
ROUND3(AA,BB,CC,DD, 5, 4, 33);
ROUND3(DD,AA,BB,CC, 8, 11, 34);
ROUND3(CC,DD,AA,BB, 11, 16, 35);
ROUND3(BB,CC,DD,AA, 14, 23, 36);
ROUND3(AA,BB,CC,DD, 1, 4, 37);
ROUND3(DD,AA,BB,CC, 4, 11, 38);
ROUND3(CC,DD,AA,BB, 7, 16, 39);
ROUND3(BB,CC,DD,AA, 10, 23, 40);
ROUND3(AA,BB,CC,DD, 13, 4, 41);
ROUND3(DD,AA,BB,CC, 0, 11, 42);
ROUND3(CC,DD,AA,BB, 3, 16, 43);
ROUND3(BB,CC,DD,AA, 6, 23, 44);
ROUND3(AA,BB,CC,DD, 9, 4, 45);
ROUND3(DD,AA,BB,CC, 12, 11, 46);
ROUND3(CC,DD,AA,BB, 15, 16, 47);
ROUND3(BB,CC,DD,AA, 2, 23, 48);
ROUND4(AA,BB,CC,DD, 0, 6, 49);
ROUND4(DD,AA,BB,CC, 7, 10, 50);
ROUND4(CC,DD,AA,BB, 14, 15, 51);
ROUND4(BB,CC,DD,AA, 5, 21, 52);
ROUND4(AA,BB,CC,DD, 12, 6, 53);
ROUND4(DD,AA,BB,CC, 3, 10, 54);
ROUND4(CC,DD,AA,BB, 10, 15, 55);
ROUND4(BB,CC,DD,AA, 1, 21, 56);
ROUND4(AA,BB,CC,DD, 8, 6, 57);
ROUND4(DD,AA,BB,CC, 15, 10, 58);
ROUND4(CC,DD,AA,BB, 6, 15, 59);
ROUND4(BB,CC,DD,AA, 13, 21, 60);
ROUND4(AA,BB,CC,DD, 4, 6, 61);
ROUND4(DD,AA,BB,CC, 11, 10, 62);
ROUND4(CC,DD,AA,BB, 2, 15, 63);
ROUND4(BB,CC,DD,AA, 9, 21, 64);
content->A += AA;
content->B += BB;
content->C += CC;
content->D += DD;
}
union MD5Buff {
MD5_word words[16];
struct append_buff{
unsigned char chars[56];
MD5_word size[2];
} append;
};
void byteSwap(MD5_word *buf, unsigned words){
#ifdef BIG_ENDIAN
unsigned char *p = (unsigned char *)buf;
do {
*buf++ = (MD5_word) ( ((unsigned)p[3] )| ((unsigned) p[2] <<8)
| ((unsigned)p[1] << 16 ) | ((unsigned p[0]) << 24 ) );
p += 4;
} while (--words);
#endif
}
struct MD5Content MD5(const unsigned char * buff_ , MD5_uint64 size_ ) {
MD5Content content;
content.A = A_init;
content.B = B_init;
content.C = C_init;
content.D = D_init;
MD5_uint64 left_size = size_ ;
const unsigned char * next = buff_;
MD5Buff buff;
while( left_size >= 64 ) {
memcpy(buff.words,next,64);
byteSwap(buff.words , 16) ;
MD5_16Word(buff.words,&content);
next += 64 ;
left_size -= 64 ;
}
memset(buff.words , 0 , 64 );
if(left_size > 0 ){
memcpy(buff.append.chars,next,left_size);
}
buff.append.chars[left_size] = 0x80;
if( left_size < 55 ) {
buff.append.size[1] = (MD5_word)(((size_<<3) & ( 0xffff0000ULL) ) >> 32 ) ;
buff.append.size[0] = (MD5_word)(((size_<<3) & ( 0x0000ffffULL) ) ) ;
}
byteSwap(buff.words , 16) ;
MD5_16Word(buff.words,&content);
if( left_size > 55) {
memset(buff.words , 0 , 64 );
buff.append.size[1] = (MD5_word)((size_<<3 & ( 0xffff0000ULL) ) >> 32 ) ;
buff.append.size[0] = (MD5_word)((size_<<3 & ( 0x0000ffffULL) ) ) ;
byteSwap(buff.words , 16) ;
MD5_16Word(buff.words,&content);
}
return content;
}
inline std::string GetMD5(unsigned char *buf, size_t len) {
auto content = MD5((unsigned char *)buf, (unsigned long long ) len );
MD5Result ret;
ret.content = content;
std::ostringstream ost;
for( int i = 0 ; i < 16 ; i ++ ) {
ost.width(2);
ost.fill('0');
ost<<std::hex<<short(ret.buff[i]);
}
return ost.str();
}