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. rpcserver不可用

    今天用打印机.电脑一直弹出rpcserver不可用.如图: 解决的方法:将例如以下服务启动就可以解决,如图:

  2. CHtmlEditCtrl (2): Add a Source Text Editor to Your HTML Editor

    In a previous article, I described how to create an HTML editor using the MFC CHtmlEditCtrl class in ...

  3. Provider Pattern for Beginners in .net

    Download ProviderPattern.zip Introduction Provider pattern allows the developers to create pluggable ...

  4. USACO Arithmetic Progressions(暴力)

    题目请点我 题解: 这道题的题意是找出集合里全部固定长度为N的等差数列.集合内的元素均为P^2+q^2的形式(0<=p,q<=M).时间要求5s内.本着KISS,直接暴力. 可是后来竟超时 ...

  5. 基于VM10+Win7安装Mac OSX10.11 El Capitan

    前言 此文写给那些像我一样的屌丝程序员(呵呵,我现在从事的是最底层的工作了,但是不想放弃我的梦想) 说明 基于VM10+Win7安装Mac OSX10.11 El Capitan 工具 VMware- ...

  6. JAVA 报错exe4j中this executable was created with an evaluation 怎么办

    如果使用未破解注册的exe4j打包JAR文件为EXE,运行EXE的时候就会出现下面的提示   打开exe4j软件,Change License或者是输入序列号,然后用注册机算一个注册码即可  

  7. 在浏览器判断是否安装app,并打开相应的页面

    1.代码功能: 判断手机/平板是否安装app 如果安装 则调用app的scheme,传入url当作参数,来做后续操作 如果没有安装 则跳转到app store/google play 下载app 2. ...

  8. sublime text执行PHP代码

    新建编译系统 { "cmd": ["php", "$file"], "file_regex": "php$&q ...

  9. JavaScript的valueOf和toString

    深度好文 http://www.cnblogs.com/coco1s/p/6509141.html 知识要点 不同对象调用valueOf和toString的顺序不一样 高阶函数的使用,替代for循环 ...

  10. Win10 PLSQL 登录后,提示数据库字符集(AL32UTF8)和客户端字符集(ZHS16GBK)不一致

    plsql 登录后提示: Database character set (AL32UTF8) and Client character set (ZHS16GBK) are different.Cha ...