单纯md5的一个具体实现

/*

* 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;

}


 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值