1.什么是MD5

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。——百度百科

MD5其实不算是加密算法,而是一种信息的摘要。它的特性是不可逆的,所以除了暴力破解 一般逆序算法是得不到结果的。例如:使用如下算法进行加密,对一个字符串利用它的长度和每一位的ASCII相加得出值,比如“bc”那么就是2+98+99=199,如果利用这个算法进行逆推的得出的答案就不唯一,比如"ac",“Ho”,"AAB"等等。

2.MD5加盐

如果直接对密码进行散列,那么黑客可以对通过获得这个密码散列值,然后通过查散列值字典(例如MD5密码破解网站),得到某用户的密码。

加Salt可以一定程度上解决这一问题。所谓加Salt方法,就是加点“佐料”。其基本想法是这样的:当用户首次提供密码时(通常是注册时),由系统自动往这个密码里撒一些“佐料”,然后再散列。而当用户登录时,系统为用户提供的代码撒上同样的“佐料”,然后散列,再比较散列值,已确定密码是否正确。

3.MD5的加密步骤

接下来大致罗列一下MD5加密的计算步骤,可以参考这个视频,MD5算法视频

1、数据填充

对消息进行数据填充,使消息的长度对512取模得448,设消息长度为X,即满足X mod 512=448。根据此公式得出需要填充的数据长度。
填充方法:在消息后面进行填充,填充第一位为1,其余为0。

2、添加消息长度

在第一步结果之后再填充上原消息的长度,可用来进行存储的长度为64位。
在此步骤进行完毕后,最终消息长度就是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++的实现:

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

MD5.cpp

/*4组计算函数*/
inline unsigned int F(unsigned int X, unsigned int Y, unsigned int Z)
{
return (X & Y) | ((~X) & Z);
}
inline unsigned int G(unsigned int X, unsigned int Y, unsigned int Z)
{
return (X & Z) | (Y & (~Z));
}
inline unsigned int H(unsigned int X, unsigned int Y, unsigned int Z)
{
return X ^ Y ^ Z;
}
inline unsigned int I(unsigned int X, unsigned int Y, unsigned int Z)
{
return Y ^ (X | (~Z));
}
/*4组计算函数结束*/ /*32位数循环左移实现函数*/
void ROL(unsigned int &s, unsigned short cx)
{
if (cx > )cx %= ;
s = (s << cx) | (s >> ( - cx));
return;
} /*B\L互转,接收UINT类型*/
void ltob(unsigned int &i)
{
unsigned int tmp = i;//保存副本
byte *psour = (byte*)&tmp, *pdes = (byte*)&i;
pdes += ;//调整指针,准备左右调转
for (short i = ; i >= ; --i)
{
CopyMemory(pdes - i, psour + i, );
}
return;
} /*
MD5循环计算函数,label=第几轮循环(1<=label<=4),lGroup数组=4个种子副本,M=数据(16组32位数指针)
种子数组排列方式: --A--D--C--B--,即 lGroup[0]=A; lGroup[1]=D; lGroup[2]=C; lGroup[3]=B;
*/
void AccLoop(unsigned short label, unsigned int *lGroup, void *M)
{
unsigned int *i1, *i2, *i3, *i4, TAcc, tmpi = ; //定义:4个指针; T表累加器; 局部变量
typedef unsigned int(*clac)(unsigned int X, unsigned int Y, unsigned int Z); //定义函数类型
const unsigned int rolarray[][] = {
{ , , , },
{ , , , },
{ , , , },
{ , , , }
};//循环左移-位数表
const unsigned short mN[][] = {
{ , , , , , , , , , , , , , , , },
{ , , , , , , , , , , , , , , , },
{ , , , , , , , , , , , , , , , },
{ , , , , , , , , , , , , , , , }
};//数据坐标表
const unsigned int *pM = static_cast<unsigned int*>(M);//转换类型为32位的Uint
TAcc = ((label - ) * ) + ; //根据第几轮循环初始化T表累加器
clac clacArr[] = { F, G, H, I }; //定义并初始化计算函数指针数组 /*一轮循环开始(16组->16次)*/
for (short i = ; i < ; ++i)
{
/*进行指针自变换*/
i1 = lGroup + (( + i) % );
i2 = lGroup + (( + i) % );
i3 = lGroup + (( + i) % );
i4 = lGroup + (( + i) % ); /*第一步计算开始: A+F(B,C,D)+M[i]+T[i+1] 注:第一步中直接计算T表*/
tmpi = (*i1 + clacArr[label - ](*i2, *i3, *i4) + pM[(mN[label - ][i])] + (unsigned int)(0x100000000UL * abs(sin((double)(TAcc + i)))));
ROL(tmpi, rolarray[label - ][i % ]);//第二步:循环左移
*i1 = *i2 + tmpi;//第三步:相加并赋值到种子
}
return;
} /*接口函数,并执行数据填充*/
unsigned int* MD5(const char* mStr)
{
unsigned int mLen = strlen(mStr); //计算字符串长度
if (mLen < ) return ;
unsigned int FillSize = - ((mLen * ) % ); //计算需填充的bit数
unsigned int FSbyte = FillSize / ; //以字节表示的填充数
unsigned int BuffLen = mLen + + FSbyte; //缓冲区长度或者说填充后的长度
unsigned char *md5Buff = new unsigned char[BuffLen]; //分配缓冲区
CopyMemory(md5Buff, mStr, mLen); //复制字符串到缓冲区 /*数据填充开始*/
md5Buff[mLen] = 0x80; //第一个bit填充1
ZeroMemory(&md5Buff[mLen + ], FSbyte - ); //其它bit填充0,另一可用函数为FillMemory
unsigned long long lenBit = mLen * 8ULL; //计算字符串长度,准备填充
CopyMemory(&md5Buff[mLen + FSbyte], &lenBit, ); //填充长度
/*数据填充结束*/ /*运算开始*/
unsigned int LoopNumber = BuffLen / ; //以64个字为一分组,计算分组数量
unsigned int A = 0x67452301, B = 0x0EFCDAB89, C = 0x98BADCFE, D = 0x10325476;//初始4个种子,小端类型
unsigned int *lGroup = new unsigned int[]{ A, D, C, B}; //种子副本数组,并作为返回值返回
for (unsigned int Bcount = ; Bcount < LoopNumber; ++Bcount) //分组大循环开始
{
/*进入4次计算的小循环*/
for (unsigned short Lcount = ; Lcount < ;)
{
AccLoop(++Lcount, lGroup, &md5Buff[Bcount * ]);
}
/*数据相加作为下一轮的种子或者最终输出*/
A = (lGroup[] += A);
B = (lGroup[] += B);
C = (lGroup[] += C);
D = (lGroup[] += D);
}
/*转换内存中的布局后才能正常显示*/
ltob(lGroup[]);
ltob(lGroup[]);
ltob(lGroup[]);
ltob(lGroup[]);
delete[] md5Buff; //清除内存并返回
return lGroup;
}

main.cpp

 #include <iostream>
#include <string.h>
#include <stdlib.h>
#include "MD5.h" int main(int argc, char **argv)
{
char tmpstr[], buf[][];
std::cout << "请输入要加密的字符串:";
std::cin >> tmpstr;
unsigned int* tmpGroup = MD5(tmpstr);
sprintf_s(buf[], "%8X", tmpGroup[]);
sprintf_s(buf[], "%8X", tmpGroup[]);
sprintf_s(buf[], "%8X", tmpGroup[]);
sprintf_s(buf[], "%8X", tmpGroup[]);
std::cout <<"MD5:"<< buf[] << buf[] << buf[] << buf[] << std::endl; delete[] tmpGroup;
return ; //在此下断点才能看到输出的值
}

【算法】MD5加密的更多相关文章

  1. MD5加密、时间戳转换、base64算法加密、解密

    #region MD5加密 /// <summary> /// MD5加密 /// </summary> /// <param name="str"& ...

  2. md5加密以及可逆的加密解密算法

    md5加密 package gov.mof.fasp2.gcfr.adjustoffset.adjust; import java.security.MessageDigest; public cla ...

  3. 常见的加密解密算法-MD5

    一.MD5加密概述 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 13 ...

  4. java中使用MD5加密的算法

    MD5,全名Message Digest Algorithm 5,中文名为消息摘要算法第五版,为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.以下是JAVA语言中使用MD5加密的工具 ...

  5. 常见的加密和解密算法—MD5

    一.MD5加密概述 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 13 ...

  6. 常见的哈希Hash算法 & MD5 & 对称非对称加密 & 海明码

    参考 Link 另外,这篇文章也提到了利用Hash碰撞而产生DOS攻击的案例: http://www.cnblogs.com/charlesblc/p/5990475.html DJB的算法实现核心是 ...

  7. c# aes,des,md5加密等解密算法

    一:可逆加密,即是能加密也能解密 对称可逆加密:加密后能解密回原文,加密key和解密key是一个 加密算法都是公开的,密钥是保密的, 即使拿到密文 你是推算不了密钥 也推算不了原文 加密解密的速度快, ...

  8. C#MD5加密和DES加密解密算法

    public partial class stringTest : System.Web.UI.Page     {         protected void Page_Load(object s ...

  9. c#进行MD5加密方式和解密算法

    --------------- 因为加密个解密都需要用到key所有在加密的后需要把key和加密码都存到数据库中 /// <summary> /// 唯一加密方式 /// </summ ...

随机推荐

  1. Docker登录失败

      % docker login Username: xxxx Password: Email: xxxxxxx@yahoo.co.jp FATA[0033] Error response from ...

  2. Spatis service单元测试: 使用mock mapper的方式

    转载:https://blog.csdn.net/atec2000/article/details/54346242 @RunWith(MockitoJUnitRunner.class)public ...

  3. maven中的snapshot来源与注意事项

    maven中的snapshot来源与注意事项 (2012-04-23 15:37:48) 转载▼ 标签: 杂谈 分类: java maven的依赖管理是基于版本管理的,在maven2之后,把版本管理细 ...

  4. 解析Linux操作系统文件目录

    解析Linux操作系统文件目录 随着Linux的不断发展,越来越多的人开始使用Linux,对于那些刚刚接触的人来说,恐怕最先感到困惑的就是那些“不明不白”的目录了.如果想熟练使用Linux,让Linu ...

  5. 手机wap适配

    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scal ...

  6. CXF实战之拦截器Interceptor(四)

    拦截器(Interceptor)是CXF功能最基本的扩展点,能够在不正确核心模块进行改动的情况下.动态加入非常多功能.拦截器和JAX-WS Handler.Filter的功能相似,当服务被调用时.就会 ...

  7. 在Ubuntu系统上搭建Hadoop 2.x(2.6.2)

    官方的中文版的Hadoop快速入门教程已经是很老的版本了,新版的Hadoop目录结构发生了变化,因此一些配置文件的位置也略微调整了,例如新版的hadoop中找不到快速入门中提到的conf目录,另外,网 ...

  8. IDEA 之 “There is no configured/running web-servers found!...”

    首次配置 IDEA 2017.1.1 与 Tomcat9.0 的 java 开发环境. 在配置成功并创建第一个 Web Application(3.1) 项目后,运行或调试正常运行. 直接在 jsp ...

  9. WinForm 之 程序退出

    一.关闭窗体 在c#中退出WinForm程序包括有很多方法,如:this.Close(); Application.Exit();Application.ExitThread(); System.En ...

  10. MAVEN创建JAVA的Web工程

    maven命令:http://blog.csdn.net/edward0830ly/article/details/8748986 1.创建MAVEN的Web工程 mvn archetype:gene ...