MD5加密算法原理及实现

MD5消息摘要算法,属Hash算法一类。MD5算法对输入任意长度的消息进行运行,产生一个128位的消息摘要。

以下所描述的消息长度、填充数据都以位(Bit)为单位,字节序为小端字节。

算法原理

1、数据填充

对消息进行数据填充,使消息的长度对512取模得448,设消息长度为X,即满足X mod 512=448。根据此公式得出需要填充的数据长度。

填充方法:在消息后面进行填充,填充第一位为1,其余为0。

2、添加消息长度

在第一步结果之后再填充上原消息的长度,可用来进行的存储长度为64位。如果消息长度大于264,则只使用其低64位的值,即(消息长度 对 264取模)。

在此步骤进行完毕后,最终消息长度就是512的整数倍。

3、数据处理

准备需要用到的数据:

  • 4个常数: A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;
  • 4个函数:F(X,Y,Z)=(X & Y) | ((~X) & Z); G(X,Y,Z)=(X & Z) | (Y & (~Z));  H(X,Y,Z)=X ^ Y ^ Z; I(X,Y,Z)=Y ^ (X | (~Z));

把消息分以512位为一分组进行处理,每一个分组进行4轮变换,以上面所说4个常数为起始变量进行计算,重新输出4个变量,以这4个变量再进行下一分组的运算,如果已经是最后一个分组,则这4个变量为最后的结果,即MD5值。

具体计算的实现较为复杂,建议查阅相关书籍,下面给出在C++上的实现代码。

代码实现

#MD5.h

 1 #ifndef MD5H
 2 #define MD5H
 3 #include <math.h>
 4 #include <Windows.h>
 5
 6 void ROL(unsigned int &s, unsigned short cx); //32位数循环左移实现函数
 7 void ltob(unsigned int &i); //B\L互转,接受UINT类型
 8 unsigned int* MD5(const char* mStr); //接口函数,并执行数据填充,计算MD5时调用此函数
 9
10 #endif

#MD5.cpp

  1 #include "MD5.h"
  2
  3 /*4组计算函数*/
  4 inline unsigned int F(unsigned int X, unsigned int Y, unsigned int Z)
  5 {
  6     return (X & Y) | ((~X) & Z);
  7 }
  8 inline unsigned int G(unsigned int X, unsigned int Y, unsigned int Z)
  9 {
 10     return (X & Z) | (Y & (~Z));
 11 }
 12 inline unsigned int H(unsigned int X, unsigned int Y, unsigned int Z)
 13 {
 14     return X ^ Y ^ Z;
 15 }
 16 inline unsigned int I(unsigned int X, unsigned int Y, unsigned int Z)
 17 {
 18     return Y ^ (X | (~Z));
 19 }
 20 /*4组计算函数结束*/
 21
 22 /*32位数循环左移实现函数*/
 23 void ROL(unsigned int &s, unsigned short cx)
 24 {
 25     if (cx > 32)cx %= 32;
 26     s = (s << cx) | (s >> (32 - cx));
 27     return;
 28 }
 29
 30 /*B\L互转,接收UINT类型*/
 31 void ltob(unsigned int &i)
 32 {
 33     unsigned int tmp = i;//保存副本
 34     byte *psour = (byte*)&tmp, *pdes = (byte*)&i;
 35     pdes += 3;//调整指针,准备左右调转
 36     for (short i = 3; i >= 0; --i)
 37     {
 38         CopyMemory(pdes - i, psour + i, 1);
 39     }
 40     return;
 41 }
 42
 43 /*
 44 MD5循环计算函数,label=第几轮循环(1<=label<=4),lGroup数组=4个种子副本,M=数据(16组32位数指针)
 45 种子数组排列方式: --A--D--C--B--,即 lGroup[0]=A; lGroup[1]=D; lGroup[2]=C; lGroup[3]=B;
 46 */
 47 void AccLoop(unsigned short label, unsigned int *lGroup, void *M)
 48 {
 49     unsigned int *i1, *i2, *i3, *i4, TAcc, tmpi = 0; //定义:4个指针; T表累加器; 局部变量
 50     typedef unsigned int(*clac)(unsigned int X, unsigned int Y, unsigned int Z); //定义函数类型
 51     const unsigned int rolarray[4][4] = {
 52         { 7, 12, 17, 22 },
 53         { 5, 9, 14, 20 },
 54         { 4, 11, 16, 23 },
 55         { 6, 10, 15, 21 }
 56     };//循环左移-位数表
 57     const unsigned short mN[4][16] = {
 58         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
 59         { 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 },
 60         { 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 },
 61         { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }
 62     };//数据坐标表
 63     const unsigned int *pM = static_cast<unsigned int*>(M);//转换类型为32位的Uint
 64     TAcc = ((label - 1) * 16) + 1; //根据第几轮循环初始化T表累加器
 65     clac clacArr[4] = { F, G, H, I }; //定义并初始化计算函数指针数组
 66
 67     /*一轮循环开始(16组->16次)*/
 68     for (short i = 0; i < 16; ++i)
 69     {
 70         /*进行指针自变换*/
 71         i1 = lGroup + ((0 + i) % 4);
 72         i2 = lGroup + ((3 + i) % 4);
 73         i3 = lGroup + ((2 + i) % 4);
 74         i4 = lGroup + ((1 + i) % 4);
 75
 76         /*第一步计算开始: A+F(B,C,D)+M[i]+T[i+1] 注:第一步中直接计算T表*/
 77         tmpi = (*i1 + clacArr[label - 1](*i2, *i3, *i4) + pM[(mN[label - 1][i])] + (unsigned int)(0x100000000UL * abs(sin((double)(TAcc + i)))));
 78         ROL(tmpi, rolarray[label - 1][i % 4]);//第二步:循环左移
 79         *i1 = *i2 + tmpi;//第三步:相加并赋值到种子
 80     }
 81     return;
 82 }
 83
 84 /*接口函数,并执行数据填充*/
 85 unsigned int* MD5(const char* mStr)
 86 {
 87     unsigned int mLen = strlen(mStr); //计算字符串长度
 88     if (mLen < 0) return 0;
 89     unsigned int FillSize = 448 - ((mLen * 8) % 512); //计算需填充的bit数
 90     unsigned int FSbyte = FillSize / 8; //以字节表示的填充数
 91     unsigned int BuffLen = mLen + 8 + FSbyte; //缓冲区长度或者说填充后的长度
 92     unsigned char *md5Buff = new unsigned char[BuffLen]; //分配缓冲区
 93     CopyMemory(md5Buff, mStr, mLen); //复制字符串到缓冲区
 94
 95     /*数据填充开始*/
 96     md5Buff[mLen] = 0x80; //第一个bit填充1
 97     ZeroMemory(&md5Buff[mLen + 1], FSbyte - 1); //其它bit填充0,另一可用函数为FillMemory
 98     unsigned long long lenBit = mLen * 8ULL; //计算字符串长度,准备填充
 99     CopyMemory(&md5Buff[mLen + FSbyte], &lenBit, 8); //填充长度
100     /*数据填充结束*/
101
102     /*运算开始*/
103     unsigned int LoopNumber = BuffLen / 64; //以16个字节为一分组,计算分组数量
104     unsigned int A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;//初始4个种子,小端类型
105     unsigned int *lGroup = new unsigned int[4]{ A, D, C, B}; //种子副本数组,并作为返回值返回
106     for (unsigned int Bcount = 0; Bcount < LoopNumber; ++Bcount) //分组大循环开始
107     {
108         /*进入4次计算的小循环*/
109         for (unsigned short Lcount = 0; Lcount < 4;)
110         {
111             AccLoop(++Lcount, lGroup, &md5Buff[Bcount * 16]);
112         }
113         /*数据相加作为下一轮的种子或者最终输出*/
114         A = (lGroup[0] += A);
115         B = (lGroup[3] += B);
116         C = (lGroup[2] += C);
117         D = (lGroup[1] += D);
118     }
119     /*由于内存中的为大端字节,转成小端才能正常显示*/
120     ltob(lGroup[0]);
121     ltob(lGroup[1]);
122     ltob(lGroup[2]);
123     ltob(lGroup[3]);
124     delete[] md5Buff; //清除内存并返回
125     return lGroup;
126 }

再给出调用实例(以win32控制台应用程序为例):

#main.cpp

 1 #include <iostream>
 2 #include <string.h>
 3 #include <stdlib.h>
 4 #include "MD5.h"
 5
 6 int main(int argc, char **argv)
 7 {
 8     char tmpstr[256], buf[4][10];
 9     std::cout << "请输入要加密的字符串:";
10     std::cin >> tmpstr;
11     unsigned int* tmpGroup = MD5(tmpstr);
12     sprintf_s(buf[0], "%8X", tmpGroup[0]);
13     sprintf_s(buf[1], "%8X", tmpGroup[3]);
14     sprintf_s(buf[2], "%8X", tmpGroup[2]);
15     sprintf_s(buf[3], "%8X", tmpGroup[1]);
16     std::cout <<"MD5:"<< buf[0] << buf[1] << buf[2] << buf[3] << std::endl;
17
18     delete[] tmpGroup;
19     return 0; //在此下断点才能看到输出的值
20 }

注:以上代码在VS2013上编译通过

时间: 2024-10-08 07:11:18

MD5加密算法原理及实现的相关文章

[转载]MD5加密算法原理

本文转载自: http://blog.csdn.net/forgotaboutgirl/article/details/7258109 需要视频版的可以看一下泰克老林讲的MD5原理 下载地址: 网速太卡,周末上传后补上.... MD5(单向散列算法)的全称是Message-Digest Algorithm 5(信息-摘要算法),经MD2.MD3和MD4发展而来.MD5算法的使用不需要支付任何版权费用. MD5功能: 输入任意长度的信息,经过处理,输出为128位的信息(数字指纹): 不同的输入得到

MD5加密算法原理(含代码)以及SHA算法相关信息

转载: http://blog.csdn.net/forgotaboutgirl/article/details/7258109 java代码部分 亲测通过. 这里 就 只贴一下代码吧 . 动作只有 或与非,异或,位移 5个操作,但是组合得很复杂. 四个线性函数(&是与,|是或,~是非,^是异或) <<<s表示循环左移s位 package com.md5Impl; public class MD5 { static final String hexs[] = {"0&q

MD5加密算法的识别

通过MD5加密算法原理的介绍,会了解到MD5在加密的过程中,有几个固定的流程(特征),在逆向分析的过程中通过这些特征可以识别出当前使用的是MD5的加密算法,从而更高效的分析还原算法. 整理下MD5加密的几个特征: 1. 处理的数据是512位为1组,补位数据的填充方式 2. 4个初始常数 A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L (4个初始常数的值为主要特征) 3. 4轮Hash运算 (每轮的移位次数及运算的常量为主要特征) 第

java加密算法小结(2)--MD5加密算法

上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇来整理一下一个被广泛应用的加密算法---MD5. 简单了解 MD5(Message Digest Algorithm 5),翻译过来是消息摘要算法第五版,按照惯例,我们推理可能也有MD2,MD3这样名字的历史版本.. 即使完全不了解这个算法的原理,我们也可以从命名中看出一些眉道,所谓摘要,就是一个简短的概括,像我写过的毕业论文,上来第一部分就是摘要,它对后面长篇大论的文章做了一个简短有力的概

java加密算法小结--MD5加密算法

上一篇文章整理了Base64算法的相关知识,严格来说,Base64只能算是一种编码方式而非加密算法,这一篇来整理一下一个被广泛应用的加密算法---MD5. 简单了解 MD5(Message Digest Algorithm 5),翻译过来是消息摘要算法第五版,按照惯例,我们推理可能也有MD2,MD3这样名字的历史版本.. 即使完全不了解这个算法的原理,我们也可以从命名中看出一些眉道,所谓摘要,就是一个简短的概括,像我写过的毕业论文,上来第一部分就是摘要,它对后面长篇大论的文章做了一个简短有力的概

MD5加密算法详细分析_C实现

MD5加密算法 本文为原创作品,转载请注明出处:http://write.blog.csdn.net/postedit/51736426--开心! 维基百科对其描述: MD5消息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致.MD5由罗纳德·李维斯特设计,于1992年公开,用以替换MD4算法.这套算法的程序在 RFC 1321 中被加以规范. 将

一起谈谈MD5加密算法

MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆:所以要解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD5算法散列之后,把得到的散列值和原始的数据形成一个一对一的映射表,通过比在表中比破解密码的MD5算法散列值,通过匹配从映射表中找出破解密码所对应的原始明文. 对信息系统或者网站系统来说,MD5算法主要用在用户注册口令的加密,对于普通强度的口令加密,可以通过以下三种方式进行破解: (1)在线查询密码.一些在线的MD

加密算法原理及DNS服务原理

1.简述常见加密算法及常见加密算法原理,最好使用图例解说在安全领域,利用密钥加密算法来对通信的过程进行加密是一种常见的安全手段.利用该手段能够保障数据安全通信的三个目标 1.数据的保密性,防止用户的数据被窃取或泄露: 2.保证数据的完整性,防止用户传输的数据被篡改: 3.通信双方的身份确认,确保数据来源与合法的用户: 而常见的密钥加密算法类型大体可以分为三类:对称加密.非对称加密.单向加密. 对称加密 对称加密算法采用单密钥加密,在通信过程中,数据发送方将原始数据分割成固定大小的块,经过密钥和加

MD5加密算法(java及js)

为了防止用户登陆过程中信息被拦截导致信息泄露,我们应该在客户端就对用户密码进行加密.浏览器提交给服务器的是加密后的信息,即使被恶意拦截,被拦截信息也已做了加密处理,现在比较安全的一种加密算法是MD5加密算法,尽管MD5是一种单向的加密算法,但网上也有破解网站,所以为了进一步提高安全性,可以进行两次md5加密,或者结合其他的加密方法如3des等进行二次加密. 代码如下: js版: var hexcase = 0; function hex_md5(a) { if (a == "") re