信息安全——MD5的实现

1.问题描述

   MD5以512比特一块的方式处理输入的消息文本,每个块又划分为十六个32比特的子块。算法的输出由四个32比特的块组成,将它们级联成一个128比特的Hash值。

①首先填充消息使填充后的长度恰好为一个比512的倍数小64的数。填充方法是附一个“1”在消息后面,再补多个“0”。然后,在其后附上64比特的消息长度(填充前)的二进制表示。算法中使用了四个32比特的变量A、B、C、D,先把这四个变量初始化为:

A=01234567,B=89ABCDEF,C=FEDCBA98,D=76543210

称它们为链接变量。

①  接着进行算法的主循环,循环的次数是消息中512比特的块的数目。

将上面四个变量复制到另外的变量中:A到AA,B到BB,C到CC,D到DD。

主循环有四轮, 每一轮由16次操作组成。F、G、H、I函数,FF、GG、HH、II四种操作详见教材各密码学参考书。所有这些步骤进行完之后,将A、B、C、D分别加上AA、BB、CC、DD,然后用下一块数据继续进行算法。

③最后的输出是A、B、C、D的级联。

2.基本要求

   以MD5(x)的形式实现,x为01串。

3. 实现提示

注意消息文本、各种变量的类型及其类型转换。

可以参考这里:www.cnblogs.com/fullsail/archive/2013/02/22/2921505.html


代码如下:

md5.h

 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
 #include <assert.h>

 #define ROTL32(dword, n) ((dword) << (n) ^ ((dword) >> (32 - (n))))
 /*MD5的结果数据长度*/
 static const unsigned int MD5_HASH_SIZE   = 16;

 /*每次处理的BLOCK的大小*/
 static const unsigned int MD5_BLOCK_SIZE = 64;
 //================================================================================================
 /*MD5的算法*/
 
 
 /*md5算法的上下文,保存一些状态,中间数据,结果*/
 typedef struct md5_ctx
 {
     /*处理的数据的长度*/
     unsigned __int64 length;
     /*还没有处理的数据长度*/
     unsigned __int64 unprocessed;
     /*取得的HASH结果(中间数据)*/
     unsigned int  hash[4];
 } md5_ctx;
 
 

 
 static void md5_init(md5_ctx *ctx)
 {
     ctx->length = 0;
     ctx->unprocessed = 0;
 
     /* initialize state */
	 /*不要奇怪为什么初始数值与参考数值不同,这是因为我们使用的数据结构的关系,大的在低位,小的在高位,8位8位一读*/
     ctx->hash[0] = 0x67452301; /*应该这样读0x01234567*/
     ctx->hash[1] = 0xefcdab89; /*0x89abcdef*/
     ctx->hash[2] = 0x98badcfe; /*0xfedcba98*/
     ctx->hash[3] = 0x10325476; /*0x76543210*/
 }
 
 #define MD5_F(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
 #define MD5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
 #define MD5_H(x, y, z) ((x) ^ (y) ^ (z))
 #define MD5_I(x, y, z) ((y) ^ ((x) | (~z)))
 
 /* 一共4轮,每一轮使用不同函数*/
 #define MD5_ROUND1(a, b, c, d, x, s, ac) {        \
         (a) += MD5_F((b), (c), (d)) + (x) + (ac); \
         (a) = ROTL32((a), (s));                   \
         (a) += (b);                               \
     }
 #define MD5_ROUND2(a, b, c, d, x, s, ac) {        \
         (a) += MD5_G((b), (c), (d)) + (x) + (ac); \
         (a) = ROTL32((a), (s));                   \
         (a) += (b);                               \
     }
 #define MD5_ROUND3(a, b, c, d, x, s, ac) {        \
         (a) += MD5_H((b), (c), (d)) + (x) + (ac); \
         (a) = ROTL32((a), (s));                   \
         (a) += (b);                               \
     }
 #define MD5_ROUND4(a, b, c, d, x, s, ac) {        \
         (a) += MD5_I((b), (c), (d)) + (x) + (ac); \
         (a) = ROTL32((a), (s));                   \
         (a) += (b);                               \
     }
 

 static void md5_process_block(unsigned int state[4], const unsigned int block[MD5_BLOCK_SIZE / 4])
 {
     register unsigned a, b, c, d;
     a = state[0];
     b = state[1];
     c = state[2];
     d = state[3];
 
     const unsigned int *x = block;
 
 
     MD5_ROUND1(a, b, c, d, x[ 0],  7, 0xd76aa478);
     MD5_ROUND1(d, a, b, c, x[ 1], 12, 0xe8c7b756);
     MD5_ROUND1(c, d, a, b, x[ 2], 17, 0x242070db);
     MD5_ROUND1(b, c, d, a, x[ 3], 22, 0xc1bdceee);
     MD5_ROUND1(a, b, c, d, x[ 4],  7, 0xf57c0faf);
     MD5_ROUND1(d, a, b, c, x[ 5], 12, 0x4787c62a);
     MD5_ROUND1(c, d, a, b, x[ 6], 17, 0xa8304613);
     MD5_ROUND1(b, c, d, a, x[ 7], 22, 0xfd469501);
     MD5_ROUND1(a, b, c, d, x[ 8],  7, 0x698098d8);
     MD5_ROUND1(d, a, b, c, x[ 9], 12, 0x8b44f7af);
     MD5_ROUND1(c, d, a, b, x[10], 17, 0xffff5bb1);
     MD5_ROUND1(b, c, d, a, x[11], 22, 0x895cd7be);
     MD5_ROUND1(a, b, c, d, x[12],  7, 0x6b901122);
     MD5_ROUND1(d, a, b, c, x[13], 12, 0xfd987193);
     MD5_ROUND1(c, d, a, b, x[14], 17, 0xa679438e);
     MD5_ROUND1(b, c, d, a, x[15], 22, 0x49b40821);
 
     MD5_ROUND2(a, b, c, d, x[ 1],  5, 0xf61e2562);
     MD5_ROUND2(d, a, b, c, x[ 6],  9, 0xc040b340);
     MD5_ROUND2(c, d, a, b, x[11], 14, 0x265e5a51);
     MD5_ROUND2(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
     MD5_ROUND2(a, b, c, d, x[ 5],  5, 0xd62f105d);
     MD5_ROUND2(d, a, b, c, x[10],  9,  0x2441453);
     MD5_ROUND2(c, d, a, b, x[15], 14, 0xd8a1e681);
     MD5_ROUND2(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
     MD5_ROUND2(a, b, c, d, x[ 9],  5, 0x21e1cde6);
     MD5_ROUND2(d, a, b, c, x[14],  9, 0xc33707d6);
     MD5_ROUND2(c, d, a, b, x[ 3], 14, 0xf4d50d87);
     MD5_ROUND2(b, c, d, a, x[ 8], 20, 0x455a14ed);
     MD5_ROUND2(a, b, c, d, x[13],  5, 0xa9e3e905);
     MD5_ROUND2(d, a, b, c, x[ 2],  9, 0xfcefa3f8);
     MD5_ROUND2(c, d, a, b, x[ 7], 14, 0x676f02d9);
     MD5_ROUND2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
 
     MD5_ROUND3(a, b, c, d, x[ 5],  4, 0xfffa3942);
     MD5_ROUND3(d, a, b, c, x[ 8], 11, 0x8771f681);
     MD5_ROUND3(c, d, a, b, x[11], 16, 0x6d9d6122);
     MD5_ROUND3(b, c, d, a, x[14], 23, 0xfde5380c);
     MD5_ROUND3(a, b, c, d, x[ 1],  4, 0xa4beea44);
     MD5_ROUND3(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
     MD5_ROUND3(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
     MD5_ROUND3(b, c, d, a, x[10], 23, 0xbebfbc70);
     MD5_ROUND3(a, b, c, d, x[13],  4, 0x289b7ec6);
     MD5_ROUND3(d, a, b, c, x[ 0], 11, 0xeaa127fa);
     MD5_ROUND3(c, d, a, b, x[ 3], 16, 0xd4ef3085);
     MD5_ROUND3(b, c, d, a, x[ 6], 23,  0x4881d05);
     MD5_ROUND3(a, b, c, d, x[ 9],  4, 0xd9d4d039);
     MD5_ROUND3(d, a, b, c, x[12], 11, 0xe6db99e5);
     MD5_ROUND3(c, d, a, b, x[15], 16, 0x1fa27cf8);
     MD5_ROUND3(b, c, d, a, x[ 2], 23, 0xc4ac5665);
 
     MD5_ROUND4(a, b, c, d, x[ 0],  6, 0xf4292244);
     MD5_ROUND4(d, a, b, c, x[ 7], 10, 0x432aff97);
     MD5_ROUND4(c, d, a, b, x[14], 15, 0xab9423a7);
     MD5_ROUND4(b, c, d, a, x[ 5], 21, 0xfc93a039);
     MD5_ROUND4(a, b, c, d, x[12],  6, 0x655b59c3);
     MD5_ROUND4(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
     MD5_ROUND4(c, d, a, b, x[10], 15, 0xffeff47d);
     MD5_ROUND4(b, c, d, a, x[ 1], 21, 0x85845dd1);
     MD5_ROUND4(a, b, c, d, x[ 8],  6, 0x6fa87e4f);
     MD5_ROUND4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
     MD5_ROUND4(c, d, a, b, x[ 6], 15, 0xa3014314);
     MD5_ROUND4(b, c, d, a, x[13], 21, 0x4e0811a1);
     MD5_ROUND4(a, b, c, d, x[ 4],  6, 0xf7537e82);
     MD5_ROUND4(d, a, b, c, x[11], 10, 0xbd3af235);
     MD5_ROUND4(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
     MD5_ROUND4(b, c, d, a, x[ 9], 21, 0xeb86d391);
 
     state[0] += a;
     state[1] += b;
     state[2] += c;
     state[3] += d;
 }
 
 
 static void md5_update(md5_ctx *ctx, const unsigned char *buf, unsigned int size)
 {
     /*为什么不是=,因为在某些环境下,可以多次调用zen_md5_update,但这种情况,必须保证前面的调用,每次都没有unprocessed*/
     ctx->length += size;
 
     /*每个处理的块都是64字节*/
     while (size >= MD5_BLOCK_SIZE)
     {
         md5_process_block(ctx->hash, reinterpret_cast<const unsigned int *>(buf));
         buf  += MD5_BLOCK_SIZE;    /*buf指针每一次向后挪动64*/
         size -= MD5_BLOCK_SIZE;   /*每一次处理64个字符*/
     }
 
     ctx->unprocessed = size;   /*未处理的字符数数目记录下来*/
 }
 
 

 static void md5_final(md5_ctx *ctx, const unsigned char *buf, unsigned int size, unsigned char *result)
 {
     unsigned int message[MD5_BLOCK_SIZE / 4];
	 memset(message, 0 ,(MD5_BLOCK_SIZE / 4) * sizeof(unsigned int));
     /*保存剩余的数据,我们要拼出最后1个(或者两个)要处理的块,前面的算法保证了,最后一个块肯定小于64个字节*/
     if (ctx->unprocessed)
     {
         memcpy(message, buf + size - ctx->unprocessed, static_cast<unsigned int>( ctx->unprocessed));
		/*================================================================================
		 这里的memcpy复制很有趣,是按照字节复制比如说buf --- 0x11 0x14 0xab 0x23 0xcd  |
		 ctx>unprocessed_=5 现在copy至 message --- 0x23ab1411 0x000000cd
		 这样的话,下面的也很好解释了!
		=================================================================================*/
     }
	   /*=================================================================================
        用法:static_cast < type-id > ( expression )
        该运算符把expression转换为type-id类型
        ==================================================================================*/

     /*得到0x80要添加在的位置(在unsigned int 数组中)*/
     unsigned int index = ((unsigned int)ctx->length & 63) >> 2;
	 /*一次性处理64个unsigned int型数据,(unsigned int)ctx->length_ & 63求出余下多少未处理的字符*/

     unsigned int shift = ((unsigned int)ctx->length & 3) * 8;
	 /*一个message里面可以放置4个字符数据,找到应该移动的位数*/
 
     /*添加0x80进去,并且把余下的空间补充0*/
     message[index++] ^= 0x80 << shift;   /*^ 位异或*/
 
     /*如果这个block还无法处理,其后面的长度无法容纳长度64bit,那么先处理这个block*/
     if (index > 14)
     {
         while (index < 16)
         {
             message[index++] = 0;
         }
 
         md5_process_block(ctx->hash, message);
         index = 0;
     }
 
     /*补0*/
     while (index < 14)
     {
         message[index++] = 0;
     }
 
     /*保存长度,注意是bit位的长度*/
     unsigned __int64 data_len = (ctx->length) << 3;
 
     message[14] = (unsigned int) (data_len & 0x00000000FFFFFFFF);
     message[15] = (unsigned int) ((data_len & 0xFFFFFFFF00000000ULL) >> 32);
 
     md5_process_block(ctx->hash, message);
     memcpy(result, &ctx->hash, MD5_HASH_SIZE);  
 }
 
 
  unsigned char* md5(const unsigned char *buf,  unsigned int  size,   unsigned char result[MD5_HASH_SIZE])  
 {  
     md5_ctx ctx;  
     md5_init(&ctx);   /*初始化*/
     md5_update(&ctx, buf, size);     
     md5_final(&ctx, buf, size, result);  
     return result;  
 }  
 

main.cpp

#include "md5.h"
#include <iostream>
#include <string>
using namespace std;

int main()
{
	string str;
	cout << "Please enter the data:" << endl;
	cin >> str;

	unsigned char result[16] ={0};
 
	md5((unsigned char*)str.c_str(), str.length(), result);
	cout << "MD5 is ";
	for (int j = 0; j < 16; j++)
	printf ("%02X", result[j]);
	cout << "."<< endl;

    system ("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值