MD5算法

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) <script type="math/tex" id="MathJax-Element-2">H_(MD5)</script>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

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页