md5
1. 附加填充位
首先对输入的报文进行填位补充,使填充后的数据长度模512后余448.
如果数据长度正好模512余448,则需增加512个填充位,也就是说填充的个数为1~512位.
填充位第一个位为1,其余全部为0.
2. 补足长度
将数据长度表示为二进制,如果长度超过64位,则截取其低64位;
如果长度不足64位,则在其高位补0.
将这个64位的报文长度补在经过填充的报文后面,使得最后的数据为512位的整数倍.
3. 初始化MD缓存器
MD5运算要用到一个128位的MD5缓存器,用来保存中间变量和最终结果.
该缓存器又可看成是4个32位的寄存器A、B、C、D,初始化为:
A: 01 23 45 67
B: 89 ab cd ef
C: fe dc ba 98
D: 76 54 32 10
4. 处理数据段
首先定义4个非线性函数F、G、H、I, 对输入的报文运算以512位数据段为单位进行处理.
对每个数据段都要进行4轮的逻辑处理,在4轮中分别使用4个不同的函数F、G、H、I.
每一轮以ABCD和当前的512位的块为输入,处理后送入ABCD(128位)
* md5.h
//
// md5.h
// md5
//
// Created by 晨辉明 on 2019/8/11.
// Copyright © 2019 晨辉明. All rights reserved.
//
#ifndef md5_h
#define md5_h
#include <iostream>
// 右移的时候,高位一定要补零,而不是补充符号位
#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)))
/**
* MD5运算要用到一个128位的MD5缓存器,用来保存中间变量和最终结果.该缓存器又可看成是4个32位的寄存器A、B、C、D,初始化为:
* A: 01 23 45 67
* B:89 ab cd ef
* C:fe dc ba 98
* D:76 54 32 10
*/
#define A 0x67452301
#define B 0xefcdab89
#define C 0x98badcfe
#define D 0x10325476
void mainLoop(unsigned int M[]);
unsigned int* add(std::string str);
std::string changeHex(int a);
std::string getMD5(std::string source);
#endif /* md5_h */
用php生成常亮数组表:
<?php
class Consts {
private static function getOne($i) {
// $a = sin(1)* pow(2, 32);
return floor( abs(sin($i+1)) * pow(2, 32));
}
const INDENT = " ";
const EOL = "\n";
public static function main() {
printf("const k = {".self::EOL);
printf(self::INDENT);
for ($i = 0; $i < 4; $i++) {
printf("0x%08x,", self::getOne($i));
}
printf(self::EOL);
$j = 0;
printf(self::INDENT);
for ($i = 4; $i < 63; $i++) {
printf("0x%08x,", self::getOne($i));
$j++;
if ($j == 5) {
printf(self::EOL);
$j = 0;
printf(self::INDENT);
}
}
printf("0x%08x%s", self::getOne($i), self::EOL);
printf("};");
}
}
Consts::main();
php Consts.php
* md5.cpp
//
// md5.cpp
// md5
//
// Created by 晨辉明 on 2019/8/11.
// Copyright © 2019 晨辉明. All rights reserved.
//
#include "md5.h"
#include <iomanip>
using std::string;
//strBaye的长度
unsigned long strlength;
//A,B,C,D的临时变量
unsigned int atemp;
unsigned int btemp;
unsigned int ctemp;
unsigned int dtemp;
//常量ti unsigned int(abs(sin(i+1))*(2pow32))
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 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};
const char str16[]="0123456789abcdef";
int printf(const char *, ...);
void mainLoop(unsigned int M[])
{
unsigned int f,g;
unsigned int a=atemp;
unsigned int b=btemp;
unsigned int c=ctemp;
unsigned int d=dtemp;
// printf("a=0x%08x, b=0x%08x, c=0x%08x, d=0x%08x\n", a, b, c, d);
for (unsigned int i = 0; i < 64; i++)
{
if(i<16){
f=F(b,c,d);
printf("f=0x%08x\n", f);
g=i;
}else if (i<32) {
// printf("b=0x%08x, c=0x%08x, d = 0x%08x, ", b, c, d);
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;
// printf("a=0x%08x, f=0x%08x, k[i]=0x%08x, g=0x%08x, m[g]=0x%08x\n", a, f, k[i], g, M[g]);
// printf("shift x=0x%08x, n=%d\n", (a+f+k[i]+M[g]), s[i] );
b = b + shift((a+f+k[i]+M[g]), s[i]);
// printf("after b=0x%08x\n", b);
a=tmp;
}
atemp=a+atemp;
btemp=b+btemp;
ctemp=c+ctemp;
dtemp=d+dtemp;
printf("a=0x%08x, b=0x%08x, c=0x%08x, d=0x%08x\n", a, b, c, d);
}
/*
*填充函数
*处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64)
*填充方式为先加一个1,其它位补零
*最后加上64位的原来长度
*/
unsigned int* add(string str)
{
unsigned long num=((str.length()+8)/64)+1; //以512位,64个字节为一组
unsigned int *strByte = new unsigned int[num*16]; //64/4=16,所以有16个整数
strlength = num*16;
for (unsigned int i = 0; i < num*16; i++)
strByte[i]=0;
for (unsigned int i=0; i <str.length(); i++) {
// 一个整数存储四个字节,i>>2表示i/4 一个unsigned int对应4个字节,保存4个字符信息
strByte[i>>2]|=(str[i])<<((i%4)*8);
}
//尾部添加1 一个unsigned int保存4个字符信息,所以用128左移
strByte[str.length()>>2]|=0x80<<(((str.length()%4))*8);
/*
*添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位
*/
strByte[num*16-2] = (unsigned int)str.length() * 8;
return strByte;
}
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;
}
string getMD5(string source)
{
atemp=A; //初始化
btemp=B;
ctemp=C;
dtemp=D;
unsigned int *strByte=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] = strByte[i*16+j];
}
for (int k = 0; k < 16; k++) {
std::cout << num[k] << ",";
}
std::cout << std::endl;
mainLoop(num);
}
return changeHex(atemp).append(changeHex(btemp)).append(changeHex(ctemp)).append(changeHex(dtemp));
}
* main.cpp
//
// main.cpp
// md5
//
// Created by 晨辉明 on 2019/8/11.
// Copyright © 2019 晨辉明. All rights reserved.
//
#include <iostream>
#include "md5.h"
using std::string;
using std::cout;
using std::endl;
int main(int argc, const char * argv[]) {
string ss;
string s = getMD5("abc1234567890");
cout << s << endl;
return 0;
}