MD5原理[百度百科]
- 格式:docx
- 大小:44.55 KB
- 文档页数:4
MD5哈希算法及其原理“ MD5算法介绍。
”MD5消息摘要算法(MD5 Message-Digest Algorithm),是在计算机领域被⼴泛使⽤的⼀种哈希算法,⽤来对信息进⾏完整性保护。
它由美国密码学家Ronald Linn Rivest设计,于1992年公开,⽤以取代MD4算法。
它的规范为RFC 1321。
MD5将⼀个任意长度的数据经过编码得到⼀个128位(16字节)的哈希值,即为MD5值。
01—MD5功能MD5算法对任意长度的消息输⼊,产⽣⼀个128位(16字节)的哈希结构输出。
在处理过程中,以512位输⼊数据块为单位。
02—MD5⽤途及特征MD5通常应⽤在以下场景:1、防篡改,保障⽂件传输可靠性如SVN中对⽂件的控制;⽂件下载过程中,⽹站提供MD5值供下载后判断⽂件是否被篡改;BT中对⽂件块进⾏校验的功能。
2、增强密码保存的安全性。
例如⽹站将⽤户密码的MD5值保存,⽽不是存储明⽂⽤户密码,当然,还会加SALT,进⼀步增强安全性。
3、数字签名在部分⽹上赌场中,使⽤MD5算法来保证过程的公平性,并使⽤随机串进⾏防碰撞,增加解码难度。
MD5算法具有以下特点:1、压缩性任意长度的数据,算出的MD5值长度都是固定的。
2、易计算从原数据计算出MD5值很容易。
3、抗修改性对原数据进⾏任何改动,哪怕只修改1个字节,所得到的MD5值都有很⼤区别。
4、强抗碰撞已知原数据和其MD5值,想找到⼀个具有相同MD5值的数据(即伪造数据)是⾮常困难的。
03—MD5算法过程⽹络中很容易找到MD5算法的相关实现代码,这⾥就不列出了。
我们只需要关⼼它的实现框架即可。
第⼀步:消息填充补长到512的倍数最后64位为消息长度(填充前的长度)的低64位⼀定要补长(64+1~512),内容为100…0(如若消息长448,则填充512+64)第⼆步:分割把结果分割为512位的块:Y0,Y1,…(每⼀个有16个32⽐特长字)第三步:计算初始化MD buffer,128位常量(4个32bit字),进⼊循环迭代,共L次每次:⼀个输⼊128位,另⼀个输⼊512位,结果输出128位,⽤于下⼀轮输⼊第四步:结果最后⼀步的输出即为散列结果128位。
MD5加密算法的原理及应用MD5(Message Digest Algorithm 5)是一种常用的哈希算法,用于将任意长度的数据加密成固定长度的(通常为128位)哈希值。
它由美国密码学家罗纳德·李维斯特(Ronald Rivest)于1992年提出,被广泛应用于网络安全、数据完整性检查和密码保护等领域。
通过对MD5算法的原理和应用进行理解,可以更好地了解MD5算法的特点和局限性。
一、原理:MD5算法的核心原理可以概括为以下几个步骤:1.填充数据:首先,需要对原数据进行填充以满足一定的要求。
填充的规则是:向原数据的尾部添加一个1和若干个0,直到满足总长度模512(即以512位为一个分组)的余数为4482.添加长度:在填充数据后,需要将原数据的长度以64位的二进制形式添加到填充后的数据尾部,这样可以保证每个分组长度为512位。
3.初始化变量:MD5算法使用四个32位的寄存器A、B、C、D作为变量,用于迭代运算。
4.循环计算:将填充和添加长度后的数据进行分组,并进行循环的运算。
MD5算法根据数据的每个分组进行64次迭代计算,并且每次迭代都会更新四个变量的值。
5.输出结果:经过循环计算后,最后输出的四个变量值即为加密后的128位哈希值。
二、应用:MD5算法在网络安全和密码保护中有着广泛的应用,主要体现在以下几个方面:1.数据完整性验证:MD5算法可以用于验证数据的完整性和防篡改性。
发送方可以通过对数据进行MD5加密后,将哈希值同数据一起发送给接收方。
接收方在接收到数据后,也对数据进行MD5加密,并将得到的哈希值与发送方发送的哈希值进行对比,如果一致,则说明数据在传输过程中没有受到篡改。
2.密码保护:MD5算法可以用于密码的存储与验证,通常将用户密码加密后存储在数据库中。
当用户登录时,系统会将用户输入的密码进行加密后与数据库中存储的密码进行比对,如果一致,则认为用户输入的密码正确。
3.数字证书验证:MD5算法可用于数字证书的验证和签名过程中。
md5碰撞原理
MD5碰撞原理是通过不断地修改输入值并计算其MD5散列值,找到与目标值相同的值的过程。
具体来说,它是一种基于哈希函数的碰撞攻击。
在MD5碰撞过程中,攻击者会尝试不同的输入组合,并使用MD5算法
计算每个输入的散列值。
如果找到与目标值相同的散列值,则成功碰撞。
由于MD5哈希函数的单向性,碰撞过程通常是一个非常耗时的过程。
请注意,MD5碰撞过程不能被用于伪造原始输入,因为找到碰撞值并不意味着找到了原始输入本身(除非攻击者能够获得相应的原始数据)。
但是,MD5碰撞原理仍然可能被用于验证数据的完整性和身份认证的某些方面,只要选择足够多的输入组合并计算相应的散列值即可。
以上信息仅供参考,建议请教计算机专业人士,获取更准确的信息。
md5校验原理范文MD5(Message Digest Algorithm 5)是一种常用的哈希函数,用于将任意长度的数据映射成固定长度(128位)的哈希值。
MD5是一种无状态、单向加密算法,它将任意长度的数据通过一个公共的算法,生成一个128位长的哈希值。
MD5校验原理主要包括以下几个方面:1.消息填充:MD5算法接收任意长度的消息作为输入,首先需要对消息进行填充以确保其长度是64的倍数。
填充分为两个步骤:第一步,在消息尾部增加一个比特1,后面跟随足够数量的0,直到长度满足对64求余得到56;第二步,在第一步结果尾部增加原始消息的长度,以64位表示。
2.初始化链变量:MD5算法使用四个32位整数作为链变量:A、B、C、D。
这四个变量初始化为特定的常数,用于存储哈希结果的中间值。
3.迭代计算:MD5算法将消息分为若干个512位的数据块(如果分完后数据长度不足512位,则按照填充规则进行填充)。
每个数据块由16个32位字组成。
a.初始化A、B、C、D:A'=AB'=BC'=CD'=Db.主循环:对每个数据块执行以下操作:-将数据块的16个字按顺序装填到缓冲区数组X[0...15]中。
-进行四轮操作,每轮操作使用不同的非线性函数:-第一轮:f(X[i],X[i+1],X[i+2])=(X[i]∧X[i+1])∨(¬X[i]∧X[i+2]) -第二轮:g(X[i],X[i+1],X[i+2])=(X[i]∧X[i+2])∨(X[i+1]∧¬X[i+2]) -第三轮:h(X[i],X[i+1],X[i+2])=X[i]⊕X[i+1]⊕X[i+2]-第四轮:i(X[i],X[i+1],X[i+2])=X[i+1]⊕(X[i]∨¬X[i+2]) -更新A、B、C、D的值:t=A+f(B,C,D)+X[k]+T[i]A=DD=CC=BB=B+((t<<s),(t>>(32-s)))-最终,加上A'、B'、C'、D'的值:A=A+A'B=B+B'C=C+C'D=D+D'c.得到最终结果:将A、B、C、D以32位的大端序方式连接起来,得到128位的哈希值。
md5算法原理MD5算法原理。
MD5(Message-Digest Algorithm 5)是一种广泛使用的哈希函数,用于产生128位(16字节)的哈希值。
它由美国密码学家罗纳德·李维斯特(Ronald Rivest)设计,于1992年公开。
MD5算法主要用于确保信息传输过程中的完整性和一致性,以及防止数据被篡改。
MD5算法的原理是将任意长度的输入信息通过一系列的处理,最终转换成128位的哈希值。
这个过程包括四轮循环运算,每轮循环包括16次操作,总共64次操作。
在每一轮循环中,都会使用不同的非线性函数、位操作和常量值进行处理,最终得到哈希值。
MD5算法的具体步骤如下:1. 填充信息,首先,要对输入信息进行填充,使其长度对512取模后余数为448。
填充的方法是在信息的末尾添加一个1和若干个0,直到满足上述条件。
然后,在末尾再添加一个64位的整数,用来表示信息的原始长度。
2. 初始化变量,MD5算法使用四个32位的寄存器(A、B、C、D)来存储中间结果。
这些寄存器的初始数值是固定的,并且与MD5算法的设计有关。
3. 循环处理,MD5算法将填充后的信息分成若干个512位的块,然后对每个块进行处理。
每个块又被分成16个32位的子块,分别记为M[0]、M[1]、...、M[15]。
4. 轮循环运算,MD5算法总共进行四轮循环运算,每轮循环包括16次操作。
在每一轮循环中,都会对寄存器A、B、C、D进行一系列的非线性函数、位操作和常量值的处理,然后得到新的寄存器数值。
5. 输出结果,经过四轮循环运算后,MD5算法得到的寄存器数值就是最终的128位哈希值。
MD5算法的设计是基于位操作和非线性函数的复杂运算,这使得它在密码学上具有较高的安全性。
然而,近年来随着计算能力的提升,MD5算法的安全性逐渐受到质疑。
因为已经发现了一些针对MD5算法的碰撞攻击,即找到两个不同的输入信息,使它们经过MD5算法处理后得到相同的哈希值。
32位md5加密原理32位MD5加密原理是一种常见的哈希算法,用于将任意长度的数据转换为固定长度的哈希值。
这种算法广泛应用于信息安全领域,用于验证数据的完整性和安全性。
在MD5算法中,输入数据经过一系列复杂的运算,最终生成一个32位的十六进制字符组成的哈希值。
MD5算法的原理主要包括四个步骤:填充、初始化、处理和输出。
首先,输入数据会被填充到一个固定长度的块中,然后通过初始化函数对初始哈希值进行设定。
接下来,数据块会被分成若干个小块,每个小块都会经过一系列的位运算和非线性函数处理。
最后,经过处理后的哈希值会被输出并作为最终的结果。
MD5算法的安全性一直备受争议,因为它存在一定的漏洞,容易受到碰撞攻击。
碰撞攻击是指找到两个不同的输入数据,使它们经过MD5算法后得到相同的哈希值。
由于MD5算法的设计不够安全,已经被证明可以通过暴力破解和彩虹表等方法进行破解。
尽管MD5算法存在一些安全性问题,但在一些场景下仍然有其实际的应用。
例如,在文件传输过程中,可以使用MD5算法生成文件的哈希值,确保文件在传输过程中没有被篡改。
此外,在用户密码存储方面,也可以使用MD5算法对密码进行加密存储,增加密码的安全性。
然而,随着计算能力的不断提高和信息安全技术的发展,MD5算法的安全性逐渐受到挑战,逐渐被更安全的哈希算法所取代。
因此,在实际应用中,建议使用更加安全可靠的哈希算法,如SHA-256等,以保障数据的安全性。
总的来说,32位MD5加密原理虽然在一定程度上可以保障数据的完整性和安全性,但其存在的安全漏洞使其逐渐被淘汰。
在实际应用中,应当根据具体情况选择更为安全可靠的加密算法,以确保数据的安全。
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.h1 #ifndef MD5H2 #define MD5H3 #include <math.h>4 #include <Windows.h>56 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时调⽤此函数910 #endif #MD5.cpp1 #include "MD5.h"23 /*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组计算函数结束*/2122 /*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 }2930 /*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 }4243 /*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位的Uint64 TAcc = ((label - 1) * 16) + 1; //根据第⼏轮循环初始化T表累加器65 clac clacArr[4] = { F, G, H, I }; //定义并初始化计算函数指针数组6667 /*⼀轮循环开始(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);7576 /*第⼀步计算开始: 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 }8384 /*接⼝函数,并执⾏数据填充*/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); //复制字符串到缓冲区9495 /*数据填充开始*/96 md5Buff[mLen] = 0x80; //第⼀个bit填充197 ZeroMemory(&md5Buff[mLen + 1], FSbyte - 1); //其它bit填充0,另⼀可⽤函数为FillMemory98 unsigned long long lenBit = mLen * 8ULL; //计算字符串长度,准备填充99 CopyMemory(&md5Buff[mLen + FSbyte], &lenBit, 8); //填充长度100 /*数据填充结束*/101102 /*运算开始*/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 * 64]);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#include <iostream>2 #include <string.h>3 #include <stdlib.h>4 #include "MD5.h"56 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;1718 delete[] tmpGroup;19 return 0; //在此下断点才能看到输出的值20 }复制代码。
浅谈使用MD5算法加密数据MD5(Message Digest Algorithm 5)是一种广泛应用于数据加密和校验的算法。
它是由美国密码学家罗纳德·李维斯特(Ronald Rivest)在1992年设计的。
MD5算法主要用于产生唯一的消息摘要,以确保数据的完整性和安全性。
它的输出是一个128位的散列值,通常用32位的16进制表示。
MD5算法的工作原理如下:1.数据分块:将待加密的数据分成512位的块进行处理。
2.填充补位:如果数据的位数不是512位的整数倍,则进行填充补位。
3.初始化处理缓冲区:使用四个32位的寄存器(A、B、C、D)作为缓冲区。
4.消息分组处理:将数据进行分组处理,每一组包含16个32位的子分组。
5.循环运算:通过四轮循环运算对数据进行处理,每轮使用不同的非线性函数和左移操作。
6.输出散列值:将最后一次循环的结果经过一系列操作得到最终的散列值。
MD5算法加密的特点:1.快速性:由于MD5算法的设计简单,执行速度非常快。
2.不可逆性:MD5算法是一种单向加密算法,加密后的散列值无法通过逆向运算得到原始数据。
3.雪崩效应:即使原数据只有微小的变化,加密后的散列值会发生巨大的变化,这种特性使得MD5算法能够有效地检测数据完整性。
4. 安全性较低:由于技术的发展,MD5算法已经被证明不是一种安全的加密算法。
由于其较短的输出长度和易受碰撞攻击(collision attack)的特性,通过碰撞攻击可以找到两个不同的输入得到相同的散列值。
因此,不建议将MD5算法用于密码存储等需要高安全性的场景。
在实际使用MD5算法加密数据时,需要注意以下几点:1. 随机盐值:为了增加数据的安全性,可以在加密过程中引入随机盐值(salt),盐值是一个随机字符串,与原始数据一同进行加密。
盐值的引入能够增加散列值的熵,防止使用彩虹表等攻击手段进行破解。
2.长度固定:无论原始数据是多长,MD5算法的输出长度是固定的,因此,无论是一段短文本还是一段较长文章,最终得到的散列值长度都是一样的。
MD5加密算法原理MD5(Message-Digest Algorithm 5)是一种常见的哈希加密算法,广泛应用于数据完整性和密码保护方面。
它是由著名的RSA数据安全公司的雇员罗纳德·李维斯特(Ronald Rivest)于1991年设计的。
MD5算法的原理是将任意长度的输入数据转换为固定长度的输出(128位),这个输出称为哈希值。
通过MD5算法,对同一输入得到的哈希值是唯一的,不同的输入得到不同的哈希值。
MD5算法的具体步骤如下:1.填充数据:根据MD5算法的规定,输入的数据需要进行填充。
填充的方式是在数据的末尾添加一个1,然后添加若干个0,直到数据的长度满足要求。
2.附加长度:将数据的原始长度(以64位二进制表示)附加到数据的末尾。
3.初始化缓冲区:创建一个128位的缓冲区,用于存储中间结果。
4.划分数据:将填充和附加长度之后的数据划分为若干个512位的分组。
5.处理分组:对每个分组进行处理。
处理的流程包括四个连续的步骤:初始化状态(将缓冲区的初始值复制到状态中),处理分组(通过一系列运算对分组进行处理),更新状态(将当前状态与处理结果合并得到新的状态),输出结果(将最后的状态转化为128位的哈希值)。
6.输出结果:将最后的128位哈希值输出。
MD5算法的核心是四个函数,分别用于不同的数据处理步骤:1.F函数:F函数是一个基本的逻辑运算,将B、C、D三个输入进行位异或、与、或的组合,得到一个32位的结果。
2.G函数:G函数与F函数类似,将C、D、A三个输入进行位异或、与、或的组合,得到一个32位的结果。
3.H函数:H函数将B、C、D三个输入进行位异或、与、非的组合,得到一个32位的结果。
4.I函数:I函数将C、B的非、A进行位异或、与的组合,得到一个32位的结果。
这四个函数在处理不同的分组时会依次循环使用,通过循环计算和更新状态来实现数据的加密。
MD5算法具有以下特点:1.哈希值唯一性:通过MD5算法得到的哈希值是唯一的,不同的输入得到不同的哈希值。
原理
对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
在MD5算法中,首先需要对信息进行填充,使其位长对512求余的结果等于448。
因此,信息的位长(Bits Length)将被扩展至N*512+448,N为一个非负整数,N可以是零。
填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。
然后,在这个结果后面附加一个以64位二进制表示的填充前信息长度。
经过这两步的处理,信息的位长=N*512+448+64= (N+1)*512,即长度恰好是512的整数倍。
这样做的原因是为满足后面处理中对信息长度的要求。
总体流程如下图所示,表示第i个分组,每次的运算都由前一轮的128位结果值和第i块512bit值进行运算。
初始的128位值为初试链接变量,这些参数用于第一轮的运算,以大端字节序来表示,他们分别为:A=0x01234567,B=0x89ABCDEF,C=0xFEDCBA98,D=0x76543210。
MD5算法的整体流程图[1]
每一分组的算法流程如下:
a)第一分组需要将上面四个链接变量复制到另外四个变量中:A到a,B到b,C 到c,D到d。
从第二分组开始的变量为上一分组的运算结果。
主循环有四轮(MD4只有三轮),每轮循环都很相似。
第一轮进行16次操作。
每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量,文本的一个子分组和一个常数。
再将所得结果向左环移一个不定的数,并加上a、b、c或d中之一。
最后用该结果取代a、b、c或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的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。
F是一个逐位运算的函数。
即,如果X,那么Y,否则Z。
函数H是逐位奇偶操作符。
假设Mj表示消息的第j个子分组(从0到15),常数ti是4294967296*abs(sin(i))的整数部分,i取值从1到64,单位是弧度。
(4294967296等于2的32次方)FF(a,b,c,d,Mj,s,ti)表示 a = b + ((a + F(b,c,d) + Mj + ti) << s)
GG(a,b,c,d,Mj,s,ti)表示 a = b + ((a + G(b,c,d) + Mj + ti) << s)
HH(a,b,c,d,Mj,s,ti)表示 a = b + ((a + H(b,c,d) + Mj + ti) << s)
Ⅱ(a,b,c,d,Mj,s,ti)表示 a = b + ((a + I(b,c,d) + Mj + ti) << s)
这四轮(64步)是:
第一轮
FF(a,b,c,d,M0,7,0xd76aa478)
FF(d,a,b,c,M1,12,0xe8c7b756)
FF(c,d,a,b,M2,17,0x242070db)
FF(b,c,d,a,M3,22,0xc1bdceee)
FF(a,b,c,d,M4,7,0xf57c0faf)
FF(d,a,b,c,M5,12,0x4787c62a)
FF(c,d,a,b,M6,17,0xa8304613)
FF(b,c,d,a,M7,22,0xfd469501)
FF(a,b,c,d,M8,7,0x698098d8)
FF(d,a,b,c,M9,12,0x8b44f7af)
FF(c,d,a,b,M10,17,0xffff5bb1)
FF(b,c,d,a,M11,22,0x895cd7be)
FF(a,b,c,d,M12,7,0x6b901122)
FF(d,a,b,c,M13,12,0xfd987193)
FF(c,d,a,b,M14,17,0xa679438e)
FF(b,c,d,a,M15,22,0x49b40821)
第二轮
GG(a,b,c,d,M1,5,0xf61e2562)
GG(d,a,b,c,M6,9,0xc040b340)GG(c,d,a,b,M11,14,0x265e5a51)GG(b,c,d,a,M0,20,0xe9b6c7aa) GG(a,b,c,d,M5,5,0xd62f105d) GG(d,a,b,c,M10,9,0x02441453)GG(c,d,a,b,M15,14,0xd8a1e681)GG(b,c,d,a,M4,20,0xe7d3fbc8)GG(a,b,c,d,M9,5,0x21e1cde6)GG(d,a,b,c,M14,9,0xc33707d6)GG(c,d,a,b,M3,14,0xf4d50d87)GG(b,c,d,a,M8,20,0x455a14ed) GG(a,b,c,d,M13,5,0xa9e3e905)GG(d,a,b,c,M2,9,0xfcefa3f8)GG(c,d,a,b,M7,14,0x676f02d9)GG(b,c,d,a,M12,20,0x8d2a4c8a) 第三轮
HH(a,b,c,d,M5,4,0xfffa3942)HH(d,a,b,c,M8,11,0x8771f681)HH(c,d,a,b,M11,16,0x6d9d6122)HH(b,c,d,a,M14,23,0xfde5380c) HH(a,b,c,d,M1,4,0xa4beea44)HH(d,a,b,c,M4,11,0x4bdecfa9)HH(c,d,a,b,M7,16,0xf6bb4b60)HH(b,c,d,a,M10,23,0xbebfbc70)HH(a,b,c,d,M13,4,0x289b7ec6)HH(d,a,b,c,M0,11,0xeaa127fa) HH(c,d,a,b,M3,16,0xd4ef3085)HH(b,c,d,a,M6,23,0x04881d05)HH(a,b,c,d,M9,4,0xd9d4d039)HH(d,a,b,c,M12,11,0xe6db99e5)HH(c,d,a,b,M15,16,0x1fa27cf8)HH(b,c,d,a,M2,23,0xc4ac5665)第四轮
Ⅱ(a,b,c,d,M0,6,0xf4292244)Ⅱ(d,a,b,c,M7,10,0x432aff97)Ⅱ(c,d,a,b,M14,15,0xab9423a7)Ⅱ(b,c,d,a,M5,21,0xfc93a039)Ⅱ(a,b,c,d,M12,6,0x655b59c3)Ⅱ(d,a,b,c,M3,10,0x8f0ccc92)Ⅱ(c,d,a,b,M10,15,0xffeff47d) Ⅱ(b,c,d,a,M1,21,0x85845dd1)Ⅱ(a,b,c,d,M8,6,0x6fa87e4f) Ⅱ(d,a,b,c,M15,10,0xfe2ce6e0) Ⅱ(c,d,a,b,M6,15,0xa3014314)
Ⅱ(b,c,d,a,M13,21,0x4e0811a1)
Ⅱ(a,b,c,d,M4,6,0xf7537e82)
Ⅱ(d,a,b,c,M11,10,0xbd3af235)
Ⅱ(c,d,a,b,M2,15,0x2ad7d2bb)
Ⅱ(b,c,d,a,M9,21,0xeb86d391)
所有这些完成之后,将A、B、C、D分别加上a、b、c、d。
然后用下一分组数据继续运行算法,最后的输出是A、B、C和D的级联。
当你按照我上面所说的方法实现MD5算法以后,你可以用以下几个信息对你做出来的程序作一个简单的测试,看看程序有没有错误。
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") =
f29939a25efabaef3b87e2cbfe641315。