转自MD5算法步骤详解

之前要写一个MD5程序,但是从网络上看到的资料基本上一样,只是讲了一个大概。经过我自己的实践,我决定写一个心得,给需要实现MD5,但又不要求很高深的编程知识的童鞋参考。不多说了,直接进入正题。

MD5算法是什么,MD5的历史由来等等我都不介绍了,想要了解的童鞋直接百度吧,见谅~~我们直接讲算法步骤。我的事例是对一个字符串进行MD5加密,没有实现对文件的MD5加密,大家看了这个事例之后应该自己能抛砖引玉了。如果想参考完整代码,可以进此查看:http://blog.csdn.net/wjl15989/article/details/8606997

步骤1:我们是对一个字符串进行MD5加密,所以我们先从字符串的处理开始。首先我们要知道一个字符的长度是8位(bit),即一个字节的长度。现在我们要做的就是将一个字符串Str1分割成每512位为一个分组,形如N*512+R,最后多出来的不足512位的R部分先填充一个1,再接无数个0,直到补足512位。这里要注意,R为0时也要补位,这时候补512位,最高位1,形如1000…00;如果R超出448,除了要补满这个分组外,还要再补上一个512位的分组(因为超过448位则不能留64位出来存放字符串的原长)。

接着,讲讲将字符串分块保存部分。一个512位的字符串分组要分成16个32位的子分组,在每个32位中,以字节为单位通过小端规则存入一个32位的变量中,可以考虑用int类型的变量(一个int变量32位),也可以考虑用unsigned
int,这样之后涉及的循环移位就不用考虑符号位了,这里还是以int为例。因为一个字符就是一个字节(8位),所以一个int类型变量能存放4个字符,假设一个字符串abcd,那么存在一个int类型变量中就是cdab。因此这里我们将字符串每4个字符分成一块,每一个块都以小端规则存放在一个int类型的变量中。估计有的人不清楚小端规则(Little-Endian),可以上网查,这里就不详细说了,见谅~

补充好后的Str2长度为(N+1)*512位(如果R超出448,则是(N+2)*512),此时最低的64位预留,用来存放之前str1的长度length(长度为字符个数*8
bit)的值,如果这个length值的二进制位数大于64位,则只保留最低的64位。将这个64位的length放入之前填充好的str2的最后64位又要注意了:将length的64位分成4个16位,相当于4位2^16进制的数,再对这个数用小端规则排列,分别填入预留的64位。之前我就是这点没有领悟,估计大家也不是很懂,我举个例子:假设64位分成ABCD(A,B,C,D分别表示16位的二进制数,A是高位,D是低位),按小端规则排列后就是CDAB,将形如CDAB的64位按C(高位)到B(低位)的顺序填入str2预留的64位。

至此,补位的思想已经讲完了,这里再讲讲我的具体实现。我的思路是用一个长度为16的int类型的数组int
M[16]。因为一个int类型数据有32位,16个加起来刚好一共512位,是一个分组的长度。我刚好就按顺序M[0]…M[15]表示一个512位的数。我再声明一个容器vector,用来存放每个M[16],因为分组个数不一定只有一个。

最后我举个例子方便大家理解。首先介绍一些常识:a – 61, b – 62, c – 63, d – 64, e – 65。这里“a
– 61”表示a的ASCII码十六进制表示是0x61,其他以此类推。

好,假设一个字符串abcde,一共5个字符,长度length 为 5*
8 = 40 = 0x28。512位转化成十六进制就是64位。原字符串十六进制表示:61
62 63 64 65 00 00…00。完成补位后共512位,只有1个分组,形如: 61
62 63 64 65 80 00… 00(“80”的二进制是1000
0000,即之前的先补一个1,再补很多0的做法)。一个int
M[16]的数组就够存了,即

M[0] = 64 63 62 61,

M[1] = 00 00 80 65,

M[2] = 0,

M[3] = 0

M[14] = 00 00 00 28,

M[15] = 0

M[0]~M[15]设好之后,在内存中就是这样存的61
62 63 64 65 80 00…00(注意这里我们用MD5处理字符串时都考虑内存中的数据的排列顺序,得出的MD5也是需要按内存中的数据输出,所以经常要用小端规则转换)

看完这个例子,大家应该对步骤1的内容有比较全面的了解了

步骤2:MD5有四个32位的被称作链接变量的整数参数,我们进行如下设置:

A=0x67452301,

B=0xefcdab89,

C=0x98badcfe,

D=0x10325476。

数据这样设置之后,存在内存中就按小端规则排列:01 23 45 67 89 ab cd ef …32 10

再声明四个中间变量a,b,c,d,赋值:a
= A, b = B, c = C, d = D。

接着再设置四个非线性函数:

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))

(&是与,|是或,~是非,^是异或)

这四个函数的说明:如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。

假设M[j]表示消息的第j个子分组(从0到15),<<<s表示循环左移s,常数ti是4294967296*abs(sin(i))的整数部分,i取值从1到64,单位是弧度。(4294967296等于2的32次方)

FF(a, b, c, d, M[j], s, ti)表示 a
= b + ((a + F(b, c, d) + Mj + ti) <<< s)

GG(a, b, c, d, M[j], s, ti)表示 a
= b + ((a + G(b, c, d) + Mj + ti) <<< s)

HH(a, b, c, d, M[j], s, ti)表示 a
= b + ((a + H(b, c, d) + Mj + ti) <<< s)

II(a, b, c, d, M[j], s, ti)表示 a
= b + ((a + I(b, c, d) + Mj + ti) <<< s)

要确保形参a在内存中的值改变了,可以在形参中用按引用调用(&a),或返回a值取代原来a值。

步骤3:接下来就是要进行一个MD5算法的主要循环了,这个循环的循环次数为512位分组的个数(即之前提到的N+1或者N+2)。每次循环执行以下的步骤,我就不用文字表述了,直接用代码展示,相信大家能理解:

a = A; b = B; c = C; d = D;

//传说中的对M[j]的第一轮循环

FF(a,b,c,d,M[0],7,0xd76aa478);

FF(d,a,b,c,M[1],12,0xe8c7b756);

FF(c,d,a,b,M[2],17,0x242070db);

FF(b,c,d,a,M[3],22,0xc1bdceee);

FF(a,b,c,d,M[4],7,0xf57c0faf);

FF(d,a,b,c,M[5],12,0x4787c62a);

FF(c,d,a,b,M[6],17,0xa8304613);

FF(b,c,d,a,M[7],22,0xfd469501) ;

FF(a,b,c,d,M[8],7,0x698098d8) ;

FF(d,a,b,c,M[9],12,0x8b44f7af) ;

FF(c,d,a,b,M[10],17,0xffff5bb1) ;

FF(b,c,d,a,M[11],22,0x895cd7be) ;

FF(a,b,c,d,M[12],7,0x6b901122) ;

FF(d,a,b,c,M[13],12,0xfd987193) ;

FF(c,d,a,b,M[14],17,0xa679438e) ;

FF(b,c,d,a,M[15],22,0x49b40821);

//传说中对M[j]的第二轮循环

GG(a,b,c,d,M[1],5,0xf61e2562);

GG(d,a,b,c,M[6],9,0xc040b340);

GG(c,d,a,b,M[11],14,0x265e5a51);

GG(b,c,d,a,M[0],20,0xe9b6c7aa) ;

GG(a,b,c,d,M[5],5,0xd62f105d) ;

GG(d,a,b,c,M[10],9,0x02441453) ;

GG(c,d,a,b,M[15],14,0xd8a1e681);

GG(b,c,d,a,M[4],20,0xe7d3fbc8) ;

GG(a,b,c,d,M[9],5,0x21e1cde6) ;

GG(d,a,b,c,M[14],9,0xc33707d6) ;

GG(c,d,a,b,M[3],14,0xf4d50d87) ;

GG(b,c,d,a,M[8],20,0x455a14ed);

GG(a,b,c,d,M[13],5,0xa9e3e905);

GG(d,a,b,c,M[2],9,0xfcefa3f8) ;

GG(c,d,a,b,M[7],14,0x676f02d9) ;

GG(b,c,d,a,M[12],20,0x8d2a4c8a);

//传说中对M[j]的第三轮循环

HH(a,b,c,d,M[5],4,0xfffa3942);

HH(d,a,b,c,M[8],11,0x8771f681);

HH(c,d,a,b,M[11],16,0x6d9d6122);

HH(b,c,d,a,M[14],23,0xfde5380c) ;

HH(a,b,c,d,M[1],4,0xa4beea44) ;

HH(d,a,b,c,M[4],11,0x4bdecfa9) ;

HH(c,d,a,b,M[7],16,0xf6bb4b60) ;

HH(b,c,d,a,M[10],23,0xbebfbc70);

HH(a,b,c,d,M[13],4,0x289b7ec6);

HH(d,a,b,c,M[0],11,0xeaa127fa);

HH(c,d,a,b,M[3],16,0xd4ef3085);

HH(b,c,d,a,M[6],23,0x04881d05);

HH(a,b,c,d,M[9],4,0xd9d4d039);

HH(d,a,b,c,M[12],11,0xe6db99e5);

HH(c,d,a,b,M[15],16,0x1fa27cf8) ;

HH(b,c,d,a,M[2],23,0xc4ac5665);

//传说中对M[j]的第四轮循环

II(a,b,c,d,M[0],6,0xf4292244) ;

II(d,a,b,c,M[7],10,0x432aff97) ;

II(c,d,a,b,M[14],15,0xab9423a7);

II(b,c,d,a,M[5],21,0xfc93a039) ;

II(a,b,c,d,M[12],6,0x655b59c3) ;

II(d,a,b,c,M[3],10,0x8f0ccc92) ;

II(c,d,a,b,M[10],15,0xffeff47d);

II(b,c,d,a,M[1],21,0x85845dd1) ;

II(a,b,c,d,M[8],6,0x6fa87e4f) ;

II(d,a,b,c,M[15],10,0xfe2ce6e0);

II(c,d,a,b,M[6],15,0xa3014314) ;

II(b,c,d,a,M[13],21,0x4e0811a1);

II(a,b,c,d,M[4],6,0xf7537e82) ;

II(d,a,b,c,M[11],10,0xbd3af235);

II(c,d,a,b,M[2],15,0x2ad7d2bb);

II(b,c,d,a,M[9],21,0xeb86d391);

A += a;

B += b;

C += c;

D += d;

步骤4:处理完所有的512位的分组后,得到一组新的A,B,C,D的值,将这些值按ABCD的顺序级联,然后输出。这里还要注意,输出的MD5是按内存中数值的排列顺序,所以我们要分别对A,B,C,D的值做一个小端规则的转换。举个例子:A有32位,分成4个字节A1A2A3A4。输出A的时候,要这样输出:A4A3 A2A1。这样就能输出正确的MD5了。

下面给一些例子大家测试:

MD5 ("") = d41d8cd98f00b204e9800998ecf8427e

MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661

MD5 (“ab”) = 187ef4436122d1cc2f40dc2b92f0eba0

MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72

MD5 (“abcde”) = ab56b4d92b40713acc5af89985d4b786

MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0

MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b

MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") =

    f29939a25efabaef3b87e2cbfe641315

MD5算法步骤详解的更多相关文章

  1. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  2. 人工智能之深度学习-初始环境搭建(安装Anaconda3和TensorFlow2步骤详解)

    前言: 本篇文章主要讲解的是在学习人工智能之深度学习时所学到的知识和需要的环境配置(安装Anaconda3和TensorFlow2步骤详解),以及个人的心得体会,汇集成本篇文章,作为自己深度学习的总结 ...

  3. 一致性算法RAFT详解

    原帖地址:http://www.solinx.co/archives/415?utm_source=tuicool&utm_medium=referral一致性算法Raft详解背景 熟悉或了解 ...

  4. ASP.NET连接Oracle数据库的步骤详解(转)

    ASP.NET连接Oracle数据库的步骤详解   本文我们主要介绍了ASP.NET连接Oracle数据库的步骤及每个步骤需要进行的设置,希望能够对您有所帮助.   在用ASP.NET开发应用程序时, ...

  5. Oracle 11g客户端在Linux系统上的配置步骤详解

    Oracle 11g客户端在Linux系统上的配置步骤详解 2011-07-26 10:47 newhappy2008 CSDN博客 字号:T | T 本文我们主要介绍了Oracle 11g客户端在L ...

  6. centos6.4安装配置vpn服务器步骤详解

      centos6.4安装配置vpn服务器步骤详解,从安装VPN到配置VPN服务器.配置VPN服务器的路由转发功能,每一步都很详细   一.VPN服务器环境说明 操作系统:CentOS release ...

  7. 各大公司广泛使用的在线学习算法FTRL详解

    各大公司广泛使用的在线学习算法FTRL详解 现在做在线学习和CTR常常会用到逻辑回归( Logistic Regression),而传统的批量(batch)算法无法有效地处理超大规模的数据集和在线数据 ...

  8. 转】Mahout推荐算法API详解

    原博文出自于: http://blog.fens.me/mahout-recommendation-api/ 感谢! Posted: Oct 21, 2013 Tags: itemCFknnMahou ...

  9. EA创建用例图步骤详解

    EA创建用例图步骤详解 1 创建一个项目 2 选择需要的模型 3 新建模型包 4 新建图表 5 新建模型包 6 创建用户角色Actor 7 新建用例 8 关联用户和用例 9 最后整个项目浏览器目录结构 ...

随机推荐

  1. [记录]java.math.biginteger cannot be cast to java.lang.long

    可以直接使用BigInteger类型进行接收, BigInteger id = (BigInteger)QueryRunner(conn,"SELECT LAST_INSERT_ID&quo ...

  2. C#扫盲之:==/Equals /ReferenceEquals 异同的总结,相等性你真的知道吗?

    1.前言 == Equals ReferenceEquals 三个相等性测试,是.NET提供给程序员使用的三个方法,他们之间有什么联系和区别,你真的仔细研究过?虽然之前也多多少少知道一点,但是有时候又 ...

  3. 学习GraphX

    首先准备如下社交图形数据:

  4. hadoop的mapreduce过程

    http://www.cnblogs.com/sharpxiajun/p/3151395.html 下面我从逻辑实体的角度讲解mapreduce运行机制,这些按照时间顺序包括:输入分片(input s ...

  5. SQL-学习使用FOR XML PATH

    前言:本人SQL技术很烂,然后工作时间也不久,许多东西都还在学习中,说的不好的地方尽请谅解. 首先跟大家说一下我今天遇到的问题吧. 查出的数据有三列,第一列存放的是32位的GUID,Res_Name存 ...

  6. ASP.Net Core 运行在Linux(Ubuntu)

    这段时间一直在研究asp.net core部署到linux,今天终于成功了,这里分享一下我的部署过程. Linux Disibutaion:Ubuntu 14.04 Web Server:nginx. ...

  7. linux安装缺失服务

    sudo apt-get install ssh Reading package lists... Done Building dependency tree... Done Package ssh ...

  8. 在不同版本的 IIS 上使用 ASP.NET MVC

    ASP.NET MVC Framework 依赖于 URL 路由.为了利用 URL 路由,可能不得不在 Web 服务器上执行额外的配置步骤.这些步骤取决于 Internet Information S ...

  9. warning

    warning:statement has no effect [-Wunused-value]| 未能赋值,常见错误:m==1/for(i=0;i++;i<m)/

  10. 九度OJ 1528 最长回文子串 -- Manacher算法

    题目地址:http://ac.jobdu.com/problem.php?pid=1528 题目描述: 回文串就是一个正读和反读都一样的字符串,比如"level"或者"n ...