MD5算法

来源:互联网 发布:360网络电视直播 编辑:程序博客网 时间:2024/06/16 00:08

MD5算法

MD5算法简介

MD5

MD5为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。

MD5即Message Digest Algorithm (信息-摘要算法5),一种被广泛使用的密码散列函数, 使用 little-endian,输入任意不定长度信息,以512位长进行分组,生成四个32位数据,最后联合起来输出固定128位长的信息摘要可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5 不是足够安全的,因为Hans Dobbertin 在1996年找到了两个不同的 512-bit 块,它们在 MD5 计算下产生相同的 hash 值。

MD5算法特点:

1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5基本实现

输入不定长度信息,输出固定长度128-bits的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算。得出结果。

MD5算法实现

算法过程

1. 填充padding

在原始消息数据尾部填充标识 100…0,填充后的消息位数 L≡ 448 (mod 512)。至少要填充1个位,所以标识长度 1~512位。 再向上述填充好的消息尾部附加原始消息的位数的低64位,最后得到一个长度 L 是512位整数倍的消息。
填充的方法如下:

  1. 在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。
  2. 在这个结果后面附加一个以64位二进制表示的填充前信息长度(单位为Bit),如果二进制表示的填充前信息长度超过64位,则取低64位。经过这两步的处理,信息的位长=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍。这样做的原因是为满足后面处理中对信息长度的要求。

2. 分块

把填充后的消息结果分割为 L 个512位的分组:Y0, Y1, …, YL-1。
结果也表示成 N 个32位长的字 M0, M1, …, MN-1,N = L ×16。

3. 初始化变量

初始化一个128位的 MD 缓冲区,记为 CVq,也表示为4个32位
寄存器 (A, B, C, D);CV0 = IV。迭代在 MD 缓冲区进行,最后一
步的128位输出即为算法结果

寄存器 (A, B, C, D) 置16进制初值作为初始向量 IV,并采用小端
存储 (little-endian) 的存储结构:

A = 0x67452301
B = 0xEFCDAB89
C = 0x98BADCFE
D = 0x10325476

Little-Endian 将低位字节排放在内存的低地址端,高位字节排放在
内存的高地址端。相反 Big-Endian 将高位字节排放在内存的低地
址端,低位字节排放在内存的高地址端。存储结构与 CPU 体系结
构和语言编译器有关。PowerPC 系列采用 big endian 方式存储数据
,而 Intel x86系列则采用 little endian 方式存储。

4. 压缩函数

  1. MD5 压缩函数 H(MD5)MD5从 CV 输入128位,从消息分组输入512位,完成4轮循环后,输出128位,用于下一轮输入的 CV 值。
  2. 每轮循环分别固定不同的生成函数 F, G, H, I,结合指定的 T 表元素 T[] 和消息分组的不同部分 X[] 做16 次运算,生成下一轮循环的输入。
  3. 总共有64次迭代运算。
  4. 4轮循环中使用的生成函数 (轮函数) g 是一个32位非线性逻辑函数,

MD5 第 q 分组的4轮循环逻辑 (压缩函数)
这里写图片描述

在相应各轮的定义如下:

这里写图片描述
每轮循环中的一步运算逻辑
a <- b + ((a + g(b,c,d) + X[k] + T[i]) <<

C++算法代码

#include<iostream>#include<cstring>using namespace std;#define shift(x, n) (((x) << (n)) | ((x) >> (32-(n))))//定义四轮操作#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))    #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))#define H(x, y, z) ((x) ^ (y) ^ (z))#define I(x, y, z) ((y) ^ ((x) | (~z)))// 定义寄存器初始值#define A 0x67452301#define B 0xefcdab89#define C 0x98badcfe#define D 0x10325476//各轮循环左移位数const unsigned int s[] = {  7,12,17,22,7,12,17,  22,7,12,17,22,7,12,  17,22,5,9,14,20,5,  9,14,20,5,9,14,20,5,  9,14,20,4,11,16,23,  4,11,16,23,4,11,16,  23,4,11,16,23,6,10,  15,21,6,10,15,21,6,  10,15,21,6,10,15,21};//各次迭代运算采用的 T 值const unsigned int k[]={  0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,  0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,  0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be,  0x6b901122,0xfd987193,0xa679438e,0x49b40821,  0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa,  0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,  0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,  0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a,  0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c,  0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70,  0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,  0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,  0xf4292244,0x432aff97,0xab9423a7,0xfc93a039,  0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1,  0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1,  0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};const char str16[]="0123456789abcdef";unsigned int strlength;unsigned int atemp;unsigned int btemp;unsigned int ctemp;unsigned int dtemp;//迭代void iteration(unsigned int M[]) {  unsigned int f,g;  unsigned int a = atemp;  unsigned int b = btemp;  unsigned int c = ctemp;  unsigned int d = dtemp;  for (unsigned int i = 0; i < 64; i++) {    if(i < 16) {        f = F(b, c, d);        g = i;    } else if (i < 32) {        f = G(b, c, d);        g = (5 * i + 1) % 16;    } else if(i < 48) {        f = H(b, c, d);        g = (3 * i + 5) % 16;    }else{        f = I(b, c, d);        g = (7 * i) % 16;    }    unsigned int tmp = d;    d = c;    c = b;    b = b + shift((a+f + k[i] + M[g]), s[i]);    a = tmp;  }  atemp = a + atemp;  btemp = b + btemp;  ctemp = c + ctemp;  dtemp = d + dtemp;}//填充函数unsigned int* add(string str) {  unsigned int num = ((str.length() + 8) / 64) + 1;  unsigned int *byte=new unsigned int[num * 16];  strlength=num*16;  for (unsigned int i = 0; i < num*16; i++)      byte[i]=0;  for (unsigned int i = 0; i <str.length(); i++) {      byte[i >> 2] |= (str[i]) << ((i % 4) * 8);  }  byte[str.length() >> 2] |= 0x80<<(((str.length() % 4)) * 8);  byte[num * 16 - 2] = str.length() * 8;  return byte;}//逆序处理每个字节string changeHex(int a) {  int b;  string str1;  string str = "";  for(int i = 0; i < 4; i++) {    str1="";    b=((a >> i * 8) % (1 << 8)) & 0xff;    for (int j = 0; j < 2; j++) {        str1.insert(0, 1, str16[b % 16]);        b = b / 16;    }    str += str1;  }  return str;}//MD5调用流程string MD5(string source) {  atemp=A;  btemp=B;  ctemp=C;  dtemp=D;  unsigned int *byte=add(source);  for(unsigned int i=0;i<strlength/16;i++) {    unsigned int num[16];    for(unsigned int j=  0; j < 16; j++)        num[j] = byte[i * 16 + j];    iteration(num);  }  return changeHex(atemp).append(changeHex(btemp)).append(changeHex(ctemp)).append(changeHex(dtemp));}int main() {  string ss;    cin>>ss;  string s = MD5(ss);  cout<<s <<endl;  return 0;}

实验测试样例

md5(a,32) = 0cc175b9c0f1b6a831c399e269772661
md5(yes,32) = a6105c0a611b41b08f1209506350279e

原创粉丝点击