/* * md5 -- compute and check MD5 message digest. * this version only can calculate the char string. * * MD5 (Message-Digest algorithm 5) is a widely used, partially * insecure cryptographic hash function with a 128-bit hash value. * * Author: huxl * Date: Mar 07, 2012 * Version: 1.0.0 * 在linux下编译,要添加链接库,命令如:gcc -o md5 md5.c -lm */ #include <stdlib.h> #include <string.h> #include <stdio.h> #include <math.h> #define SINGLE_ONE_BIT 0x80 //十进制128,对应字符“1” #define BLOCK_SIZE 512 //512一分组 #define MOD_SIZE 448 //填充至%512=448 #define APP_SIZE 64 #define BITS 8 // MD5 Chaining Variable(链接变量) #define A 0x67452301UL #define B 0xEFCDAB89UL #define C 0x98BADCFEUL #define D 0x10325476UL // Creating own types #ifdef UINT64 # undef UINT64 #endif #ifdef UINT32 # undef UINT32 #endif typedef unsigned long long UINT64; typedef unsigned long UINT32;//64位编译器中unsigned long占8字节,本程序是否仍可用? typedef unsigned char UINT8; typedef struct { char * message; UINT64 length; }STRING; const UINT32 X[4][2] = {{0, 1}, {1, 5}, {5, 3}, {0, 7}}; // Constants for MD5 transform routine. const UINT32 S[4][4] = {//向左环移 { 7, 12, 17, 22 },//一轮中使用 { 5, 9, 14, 20 }, { 4, 11, 16, 23 }, { 6, 10, 15, 21 } }; // F, G, H and I are basic MD5 functions. UINT32 F( UINT32 X, UINT32 Y, UINT32 Z ) { return ( X & Y ) | ( ~X & Z ); } UINT32 G( UINT32 X, UINT32 Y, UINT32 Z ) { return ( X & Z ) | ( Y & ~Z ); } UINT32 H( UINT32 X, UINT32 Y, UINT32 Z ) { return X ^ Y ^ Z; } UINT32 I( UINT32 X, UINT32 Y, UINT32 Z ) { return Y ^ ( X | ~Z ); } // rotates x left s bits. UINT32 rotate_left( UINT32 x, UINT32 s ) { return ( x << s ) | ( x >> ( 32 - s ) ); } // Pre-processin //length 代表程序入口接收到的字符的个数,也即字节数 UINT32 count_padding_bits ( UINT32 length ) { UINT32 div = length * BITS / BLOCK_SIZE;//分组大小 UINT32 mod = length * BITS % BLOCK_SIZE;//不足512部分 UINT32 c_bits; if ( mod == 0 ) c_bits = MOD_SIZE;//需要添加的位数448 else c_bits = ( MOD_SIZE + BLOCK_SIZE - mod ) % BLOCK_SIZE;//需要添加的位数=448-mod return c_bits / BITS;//转成字符数,即多少字节 } //argv指向传入的字符串 STRING append_padding_bits ( char * argv ) { UINT32 msg_length = strlen ( argv ); UINT32 bit_length = count_padding_bits ( msg_length );//需要填充的字符数 UINT64 app_length = msg_length * BITS; STRING string; string.message = (char *)malloc(msg_length + bit_length + APP_SIZE / BITS);//欲摘要字符串字节数+补充字节数+8字节长度 // Save message strncpy ( string.message, argv, msg_length ); // Pad out to mod 64. memset ( string.message + msg_length, 0, bit_length );//初始化填充的部分 string.message [ msg_length ] = SINGLE_ONE_BIT;//最前面填充的一位是1 // Append length (before padding). memmove ( string.message + msg_length + bit_length, (char *)&app_length, sizeof( UINT64 ) );//最后面8字节是填充前信息字符数 string.length = msg_length + bit_length + sizeof( UINT64 ); return string; } //摘要前信息作为参数传入,多个摘要前信息可以用空格隔开,一次性计算 int main ( int argc, char *argv[] ) { STRING string; UINT32 w[16];//指向子分组 UINT32 chain[4];//链接变量 UINT32 state[4];//中间变量 UINT8 r[16]; UINT32 ( *auxi[ 4 ])( UINT32, UINT32, UINT32 ) = { F, G, H, I };//auxi是指向函数的指针数组 int roundIdx;//标识轮数 int argIdx; int sIdx;//标识环移 int wIdx;//标识子分组中的32位 int i; int j; if ( argc < 2 ) { fprintf ( stderr, "usage: %s string ...\n", argv[ 0 ] ); return EXIT_FAILURE; } for ( argIdx = 1; argIdx < argc; argIdx++ )//第一层循环:对多个信息进行摘要 { string = append_padding_bits ( argv[ argIdx ] );//填充预处理 // MD5 initialization. chain[0] = A; chain[1] = B; chain[2] = C; chain[3] = D; for ( j = 0; j < string.length; j += BLOCK_SIZE / BITS)//第二层循环:逐个分组摘要 { //将一个分组分成16个32位的子分组,每一个子分组由指向unsigned long的指针指向 memmove ( (char *)w, string.message + j, BLOCK_SIZE / BITS ); memmove ( state, chain, sizeof(chain) ); for ( roundIdx = 0; roundIdx < 4; roundIdx++ )//第三层循环:四轮 { wIdx = X[ roundIdx ][ 0 ]; sIdx = 0; for ( i = 0; i < 16; i++ )//第四层循环:一轮中的16步,每一步中使用的子分组,常数,函数中链接变量的顺序都不一样 { // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. state[sIdx] = state [ (sIdx + 1) % 4 ] + rotate_left ( state[sIdx] + ( *auxi[ roundIdx ] )( state[(sIdx+1) % 4], state[(sIdx+2) % 4], state[(sIdx+3) % 4]) + w[ wIdx ] +(UINT32)floor( (1ULL << 32) * fabs(sin( roundIdx * 16 + i + 1 )) ), S[ roundIdx ][ i % 4 ]); sIdx = ( sIdx + 3 ) % 4; wIdx = ( wIdx + X[ roundIdx ][ 1 ] ) & 0xF; } } //每轮结束更新chain chain[ 0 ] += state[ 0 ]; chain[ 1 ] += state[ 1 ]; chain[ 2 ] += state[ 2 ]; chain[ 3 ] += state[ 3 ]; } //级联 memmove ( r + 0, (char *)&chain[0], sizeof(UINT32) ); memmove ( r + 4, (char *)&chain[1], sizeof(UINT32) ); memmove ( r + 8, (char *)&chain[2], sizeof(UINT32) ); memmove ( r + 12, (char *)&chain[3], sizeof(UINT32) ); for ( i = 0; i < 16; i++ ) printf ( "%02x", r[i] ); putchar ( '\n' ); free(string.message); } return EXIT_SUCCESS; }