MD5加密算法原理及实现

时间:2022-12-25 16:17:39

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

 #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

 #include "MD5.h"

 /*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 / ; //以16个字为一分组,计算分组数量
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 * 64]);
}
/*数据相加作为下一轮的种子或者最终输出*/
A = (lGroup[] += A);
B = (lGroup[] += B);
C = (lGroup[] += C);
D = (lGroup[] += D);
}
/*转换内存中的布局后才能正常显示*/
ltob(lGroup[]);
ltob(lGroup[]);
ltob(lGroup[]);
ltob(lGroup[]);
delete[] md5Buff; //清除内存并返回
return lGroup;
}

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

#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 ; //在此下断点才能看到输出的值
}

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

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

  1. MD5加密算法原理及其应用

    MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆:所以要解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD5算法散列之后 ...

  2. 一起谈谈MD5加密算法

    MD5是一个安全的散列算法,输入两个不同的明文不会得到相同的输出值,根据输出值,不能得到原始的明文,即其过程不可逆:所以要解密MD5没有现成的算法,只能用穷举法,把可能出现的明文,用MD5算法散列之后 ...

  3. MD5加密算法测试

    在用户注册这一块,密码加密保证客户信息安全是最重要的,在网上查询了一些资料,发现加密算法比较流行的有MD5,DES和SHA. 虽然SHA与MD5通过碰撞法被破解了,但是MD5和SHA仍被公认是安全的加 ...

  4. MD5加密算法的Java版本

    网上搜索Java实现MD5的资料很多,错误的也很多. 之前编写的一个阿里云直播鉴权原理算法需要用到MD5算法,网上找了几个,都是不行,浪费了时间,现在贴一个,做备用. import java.secu ...

  5. NodeJS学习笔记 进阶 &lpar;2&rpar;Nodejs进阶:MD5加密算法&lpar;ok&rpar;

    个人总结:这篇文章讲解了Nodejs中自带模块的MD5加密算法的使用,读完这篇文章需要15分钟,其实还有一个叫utility的包在npm上,也非常好用. 摘选自网络 简介 MD5(Message-Di ...

  6. 轻松学习RSA加密算法原理

    转自:http://blog.csdn.net/sunmenggmail/article/details/11994013 http://blog.csdn.net/q376420785/articl ...

  7. MD5加密算法

    package com.bao.tools.encryption; import java.security.MessageDigest;import java.security.NoSuchAlgo ...

  8. md5加密算法c语言版

    from: http://blog.sina.com.cn/s/blog_693de6100101kcu6.html 注:以下是md5加密算法c语言版(16/32位) ---------------- ...

  9. 标准MD5加密算法

    标准MD5加密算法: public class Md5 { public static String getMd5(String s) { char hexDigits[] = { '0', '1', ...

随机推荐

  1. jquery 设置checked&equals;&quot&semi;checked&quot&semi;无效,radio未选中。。

    jquery 设置checked="checked"无效,radio未选中.. 最好还是使用.prop(),在jQuery1.6版本之前.attr存在一些bug.在1.6之后它会自 ...

  2. SQL2008附加数据库提示错误&colon;5120

    前几天在附加数据库时,出现了这个错误           在win7 x64系统上使用sql2008进行附加数据库(包括在x86系统正在使用的数据库文件,直接拷贝附加在X64系统中)时,提示无法打开文 ...

  3. 没做过编译器就是被人欺——从一道变态的i&plus;&plus;题猜编译器的行为(表达式从左往右扫描,同一变量相互影响)

    首先不要被人蒙了,如果是这样,根本编译不过: int i=1; int b=i+++++i; printf("%d %d\n", b ,i); Mingw报错:error: lva ...

  4. 【LeetCode练习题】Copy List with Random Pointer

    Copy List with Random Pointer A linked list is given such that each node contains an additional rand ...

  5. html相关介绍

    HTML(超文本标记语言)  超文本标记语言,即HTML(Hypertext Markup Language),是用于描述网页文档的一种标记语言 XHTML1.0 可扩展超文本置标语言(eXtensi ...

  6. java&period;lang&period;Class类

    第一次接触Class类是在学习 jdbc中.Class.forName()是Class类的一个静态方法,用于手动加载一个类,例如数据库驱动. 其实每一个java类都拥有或者说对应一个Class的实例对 ...

  7. java注解的实质,何为注解

    注解就是贴标签 (1)注解的作用 1,生成文档.如常用的@param 2,跟踪代码依赖性,实现替代文件的功能.在spring中,主要是减少配置. 3,编译时进行格式检查.如常用的@override ( ...

  8. Install Redis 3&period;2 on Ubuntu

    Install Redis 3.2 on Ubuntu It’s very easy to install Redis 3 on Ubuntu 16, just need to add PPA rep ...

  9. js--sort&lpar;&rpar;排序方法的使用--(笔记)

    情况1: var arr = [ 'c', 'd', 'a', 'e' ];      //都是字母的情况arr.sort();//alert( arr );                     ...

  10. 后台获取url里面加密的参数中,特殊符号&plus;获取到后端后是 一个空格的解决方法

    进行加密,加密后的参数中有个+号: 前端的url:http://mtest.cmread.com:8145/nap/p/QRcode.jsp?activityId=11206&vcode=O/ ...