MD5加密算法详解(c和c++环境下)
来源:互联网 发布:淘宝负责人电话号码 编辑:程序博客网 时间:2024/06/02 02:21
MD5 加密算法简介
以下讲解会综合字节和位两个来讲解,同时提醒一下,字典序是小端,即小地址存放低位,高地址存放高位,具体会在后续讲解中说明
数据填充
首先针对给出的数据,我们首先要进行数据填充,所谓的数据填充,就是让这个数据的字节对
如果我们设给定的数据字节数为
扩充规则:
在数据后面进行填充,填充第一个字节为
数据处理
四个默认渐变变量(自己姑且这么说):
A = 0x67452301;B = 0xEFCDAB89;C = 0x98BADCFE;D = 0x10325476;
四个数据处理函数:
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));
四个过程处理函数(
FF(a,b,c,d,M[i],s,t[j])表示a=b+((a+(F(b,c,d)+M[i]+T[j])<<< s) ; GG(a,b,c,d,M[i],s,t[j])表示a=b+((a+(G(b,c,d)+M[i]+T[j])<<< s) ; HH(a,b,c,d,M[i],s,t[j])表示a=b+((a+(H(b,c,d)+M[i]+T[j])<<< s) ; II(a,b,c,d,M[i],s,t[j])表示a=b+((a+(I(b,c,d)+M[i]+T[j])<<< s) ;
基本数据处理步骤
上一步的数据扩充已经将数据扩充为
数据处理具体步骤
首先我们取到了第一个
如果数据是0xab,0xfb,0xdd,0xdd,0x80,0x00,0x00….,那么[0xab,0xfb,0xdd,0xdd]就是第一组,[0x80,0x00,0x00,0x00]就是第二组,如此反复…
然而,虽然是这么分组的,但是将他们组成一个数字却另外有规则,就是前面稍微有点提到的小端,也许一些接触过嵌入式的朋友会对此比较了解,就是一个数的高位部分存储在高地址,也就是说,我们将要进行
通过上述这一步就会形成
接着就是过程处理函数,数据处理函数是包含在过程处理函数里面的,我们不要深入了解数据处理函数和过程处理函数,因为这是
首先就是
在无符号处理的时候,对于
过程处理函数中的位移数
然后对于M数组的数据处理的过程函数操作如下:
第一轮
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)
第四轮
II(a,b,c,d,M0,6,0xf4292244) II(d,a,b,c,M7,10,0x432aff97) II(c,d,a,b,M14,15,0xab9423a7) II(b,c,d,a,M5,21,0xfc93a039) II(a,b,c,d,M12,6,0x655b59c3) II(d,a,b,c,M3,10,0x8f0ccc92) II(c,d,a,b,M10,15,0xffeff47d) II(b,c,d,a,M1,21,0x85845dd1) II(a,b,c,d,M8,6,0x6fa87e4f) II(d,a,b,c,M15,10,0xfe2ce6e0) II(c,d,a,b,M6,15,0xa3014314) II(b,c,d,a,M13,21,0x4e0811a1) II(a,b,c,d,M4,6,0xf7537e82) II(d,a,b,c,M11,10,0xbd3af235) II(c,d,a,b,M2,15,0x2ad7d2bb) II(b,c,d,a,M9,21,0xeb86d391)
所以我们需要构造两个数组:
uint MD5::rolarray[4][4] = {//用于位移数处理 { 7, 12, 17, 22 }, { 5, 9, 14, 20 }, { 4, 11, 16, 23 }, { 6, 10, 15, 21 }};uint MD5::mN[4][16] = {//用于M数组处理 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, { 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }};
其中参数中的a,b,c,d就是最开始的四个渐变变量,他们在上述过程函数中分别处理的顺序是:
a,b,c,dd,a,b,cc,d,a,bb,c,d,a
就是将最后一个数移到第一个,我们可以用数组来处理比较方便,因为上述这么长的处理,太多了,可以通过循环来代替。
经过上述的过程函数处理后会得到新的a,b,c,d数据,然后我们用原来的A,B,C,D分别加上这a,b,c,d几个新数据。
接着就是进行第二组
当处理完后,我们会得到最终的
到此,原理讲解结束,接下来就是代码讲解了。
代码
#include <cmath>#include <cstdio>#include <vector>#include <string>#include <cstring>#include <iostream>using namespace std;typedef unsigned int uint;typedef long long LL;const int MAXN = 1e6 + 5;const int mod = 1e9 + 7;struct MD5 { typedef void (MD5::*deal_fun)(uint&, uint, uint, uint, uint, uint, uint);//用于定义函数指针数组 string init_str;//数据字符串 uint init_arr[1000];//最终的数据数组{进行扩充处理后的数据} const static int MAXN = 1e2; static uint s_state[4];//最开始的默认静态渐变变量 uint state[4];//这个也是默认渐变变量,但是会改变 static uint rolarray[4][4];//位移数组 static uint mN[4][16];//对M数组的处理 uint curM;//当前处理的直接在整个数据中的位置 uint lenZ;//数据的总长{进行扩充处理后的数据总长,这个数是64的倍数} uint offset;//需要从第几组开始处理 uint Tarr[64];//当前保存的T数组数据 uint Memory[64 + 5];//当前要处理的64个字节数据 uint M[16];//将64个字节数据分为16个数 MD5(); MD5(string str, int noffset); //数据处理函数 inline uint F(uint X, uint Y, uint Z); inline uint G(uint X, uint Y, uint Z); inline uint H(uint X, uint Y, uint Z); inline uint I(uint X, uint Y, uint Z); //循环左移函数 uint ROL(uint s, uint ws); //过程处理函数 inline void FF(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac); inline void GG(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac); inline void HH(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac); inline void II(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac); //生成T数组单个数据的函数 inline uint T(uint i); //将总数据中的64个字节移到Memory数组中 void data_Init(); //建立M数组 void create_M_arr(); //移动a,b,c,d,规则在前面介绍了 void l_data_change(uint *buf); //产生T数组 void create_T_arr(); //得到最终MD5值 string get_MD5(); //过程处理 void processing();};uint MD5::rolarray[4][4] = { { 7, 12, 17, 22 }, { 5, 9, 14, 20 }, { 4, 11, 16, 23 }, { 6, 10, 15, 21 }};uint MD5::mN[4][16] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12 }, { 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2 }, { 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 }};/*传统渐变变量0x67452301,0xefcdab89,0x98badcfe,0x10325476这四个东西是可以根据要求更改的,如果取上述几个数则和经常用的MD5算出的结果是一样的对了,由于有些数据是静态的,改变之后不会进行需要重新进行复制*/uint MD5::s_state[4] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};MD5::MD5() {}MD5::MD5(string str, int noffset = 1) { offset = noffset; curM = (noffset - 1) * 64; init_str = str; lenZ = init_str.length(); memset(init_arr, 0, sizeof(init_arr)); for(int i = 0; i < lenZ; i ++) { init_arr[i] = str[i]; } /* 将数据扩充到取模64个字节等于56个字节 第一个填充0x80,然后就是0x00了 */ if(lenZ % 64 != 56) init_arr[lenZ ++] = 0x80; while(lenZ % 64 != 56) { init_arr[lenZ ++] = 0x00; } /* 最后8个字节保存了没扩充钱位数的多少,记住是位数的个数不是字节的个数,同时是按照小端规则 */ uint lengthbits = init_str.length() * 8; init_arr[lenZ ++] = lengthbits & 0xff; init_arr[lenZ ++] = lengthbits >> 8 & 0xff; init_arr[lenZ ++] = lengthbits >> 16 & 0xff; init_arr[lenZ ++] = lengthbits >> 24 & 0xff; //因为uint最多32位所以我们只要考虑四个字节就可以了,虽然实际上要考虑64位,嘿 lenZ += 4; for(int i = 0;i < 4;i ++){ state[i] = s_state[i]; }}inline uint MD5::F(uint X, uint Y, uint Z) { return (X & Y) | ((~X) & Z);}inline uint MD5::G(uint X, uint Y, uint Z) { return (X & Z) | (Y & (~Z));}inline uint MD5::H(uint X, uint Y, uint Z) { return X ^ Y ^ Z;}inline uint MD5::I(uint X, uint Y, uint Z) { return Y ^ (X | (~Z));}uint MD5::ROL(uint s, uint ws) { return (s << ws) | (s >> (32 - ws));}inline void MD5::FF(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac) { a = ROL(a + F(b, c, d) + x + ac, s) + b; //printf("ff\n");}inline void MD5::GG(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac) { a = ROL(a + G(b, c, d) + x + ac, s) + b; //printf("gg\n");}inline void MD5::HH(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac) { a = ROL(a + H(b, c, d) + x + ac, s) + b; //printf("hh\n");}inline void MD5::II(uint &a, uint b, uint c, uint d, uint x, uint s, uint ac) { a = ROL(a + I(b, c, d) + x + ac, s) + b; //printf("ii\n");}//这里前面讲了inline uint MD5::T(uint i) { return (uint)((0xffffffff + 1LL) * abs(sin(i)));}//取64个字节放在Memory数组中void MD5::data_Init() { uint tmp = 0; for(int i = 0; i < 64; i ++) { Memory[i] = init_arr[curM + i]; } curM += 64;//变化位置}void MD5::create_T_arr() { for(int i = 1; i <= 64; i ++) { Tarr[i - 1] = T(i); }}/*这里使用了小端将数据存在M数组中,可以稍微思考一下*/void MD5::create_M_arr() { uint tmp = 0; int cnt = 0; for(int i = 0; i < 64; i += 4) { tmp = 0; for(int j = 3; j >= 0; j --) { tmp |= Memory[i + j]; if(j == 0) break; tmp <<= 8; } M[cnt ++] = tmp; }}//移动a,b,c,d,最后一个移到第一个void MD5::l_data_change(uint *buf) { uint buftmp[4] = {buf[3], buf[0], buf[1], buf[2]}; for(int i = 0; i < 4; i ++) { buf[i] = buftmp[i]; }}void MD5::processing() { uint statetmp[4]; for(int i = 0; i < 4; i ++) { statetmp[i] = state[i]; } /* 这里的处理只是为了更方便的循环 */ uint * a = &statetmp[0]; uint * b = &statetmp[1]; uint * c = &statetmp[2]; uint * d = &statetmp[3]; /* 产生M数组和T数组 */ create_M_arr(); create_T_arr(); /* 建立函数指针数组 循环处理 */ deal_fun d_fun[4] = { &MD5::FF, &MD5::GG, &MD5::HH, &MD5::II }; for(int i = 0; i < 4; i ++) { for(int j = 0; j < 16; j ++) { (this ->* d_fun[i])(*a, *b, *c, *d, M[mN[i][j]], rolarray[i][j % 4], Tarr[i * 16 + j]); l_data_change(statetmp);//交换a,b,c,d } } for(int i = 0; i < 4; i ++) { state[i] += statetmp[i]; }}string MD5::get_MD5() { string result; char tmp[15]; for(int i = 0;i < (lenZ - (offset - 1) * 64) / 64;i ++){ data_Init(); processing(); } /* 最终显示也是用小端 */ for(int i = 0; i < 4; i ++) { sprintf(tmp, "%02x", state[i] & 0xff); result += tmp; sprintf(tmp, "%02x", state[i] >> 8 & 0xff); result += tmp; sprintf(tmp, "%02x", state[i] >> 16 & 0xff); result += tmp; sprintf(tmp, "%02x", state[i] >> 24 & 0xff); result += tmp; } return result;}int main() { MD5 md1("aaaaaaaaaaaaaaaadminadminabcddddddddddddddddddddddddddddddddddddadmin",2); cout << md1.get_MD5() << endl; MD5 md2("2"); cout << md2.get_MD5() << endl; MD5 md3("1"); cout << md3.get_MD5() << endl; return 0;}
可能写的不太好,如果有什么问题,请提出,谢谢!
- MD5加密算法详解(c和c++环境下)
- C md5加密算法
- MD5 加密算法 c语言
- md5加密算法c实现
- md5加密算法c实现
- C# MD5加密算法
- C# .net MD5加密算法源代码
- MD5加密算法C语言实现
- objective-c加密算法之MD5
- C语言实现MD5加密算法
- C#MD5加密算法的实例
- md5加密算法c实现,七分注释
- md5加密算法c实现,七分注释
- MD5加密算法(c语言实现)
- 学习笔记-C语言实现MD5加密算法
- MD5加密算法(c语言实现)
- MD5、SHA-1加密算法C语言实现
- [C++] MD5加密算法原理及实现
- keras学习笔记(1)CNN网络
- C++学习笔记-----永远不要在派生类中改变虚函数的默认参数值
- 欢迎使用CSDN-markdown编辑器
- Weex Begin
- JAVA基础
- MD5加密算法详解(c和c++环境下)
- 获取屏幕的宽高
- Poedu_C++_Lesson01_20161219_为什么学C++
- 创新工场笔试题2013年校园招聘
- pdf复制到word有空格间隙和换行问题解决办法
- 学习笔记00
- 程序题——字符串逆序
- Spring事务管理
- 空洞般的生活