加密原理
大端小端
一个字节是8位即0000 0000,它能表示2^8=256个数,最大的数为255,那我们如果要表示数256,就需要两个字节即16位,
数256=0000 0001 0000 0000
,左边8位为高位。
计算机存储单位是字节,也就是这两个字节的存储必须有顺序,是先存储0000 0001,还是先存储0000 0000,就涉及到大端和小端存储。
大端存储即高位字节存放在低内存地址,低位字节存放在高内存地址
小端存储即低位字节存放在低内存地址,高位字节存放在高内存地址
256的大端存储即0000 0001 0000 0000 (低地址->高地址)
256的小端存储即0000 0000 0000 0001 (低地址->高地址)
下面都是从左往右是低地址->高地址
算法
我们首先以admin
为例,接下来从十进制和二进制两个角度来说明代码。
admin
的十进制为97 100 109 105 110 (ASCII码值),将十进制转为二进制的话01100001 01100100 01101101 01101001 01101110(大端)
MD5加密以512bit为一组,512/8=64字节
第一步,填充
首先我们的admin有5个字节40bit,需要让它填充到bit长度%512=448
即448/8=56个字节,还差56-5=51个字节,填充的时候第一位为1,剩下的为0,即
10000000 00000000(重复50次)=-128,0
(重复50次),至于为什么是-128,因为在计算机里是用补码存储的
当我们填充完之后应该达到56个字节448bit,然后进行第二次填充,还剩8个字节64bit,首先用原消息长度即admin的长度5*8=40bit来填充第一个字节,其余7个字节用0填充。即40,0(重复7次)=00101000 00000000(7次)
我们的第一步填充工作就完成了,会得到一个512bit64字节的需要加密的内容:
97 100 109 105 110 -128 0(50次) 40 0(7次)
第二步,分组
需要把512bit分为16个小组,一组32bit即4字节
那么,
M0=97 100 109 105(01100001 01100100 01101101 01101001)
M1=110 -128 0 0(01101110 10000000 00000000 00000000)
M2=0 0 0 0 (00000000 00000000 00000000 00000000)
…
M14=40 0 0 0 (00101000 00000000 00000000 00000000)
M15=0 0 0 0(00000000 00000000 00000000 00000000)
由于后面运算的需要,我们将它们转成小端存储即
M0=105 109 100 97
M1=0 0 -128 110
.....
需要注意的是,一定要进行扩大倍数,以M0为例
105需要左移24位=01101001 00000000 00000000 00000000即扩大为105*2^24
109需要左移16位=01101101 00000000 00000000
100需要左移8位=01100100 00000000
97不左移
然后这几个做按位或|
运算才能得到真正的M0=1768776801(十进制)
第三步,初始化常量
计算时,我们要用到四个常数A,B,C,D(小端)
A=0x67452301,B=0xefcdab89,C=0x98badcfe,D=0x10325476(十六进制)
所以我们刚刚把M0转成小端了,这样ABCD就不用变了,当然M0也可以不用转,这样ABCD需要转成大端存储即A=0x01234567。
//循环左移位数
static final 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
static final long t[]={
0xd76aa478L,0xe8c7b756L,0x242070dbL,0xc1bdceeeL,0xf57c0fafL,0x4787c62aL,0xa8304613L,0xfd469501L,
0x698098d8L,0x8b44f7afL,0xffff5bb1L,0x895cd7beL,0x6b901122L,0xfd987193L,0xa679438eL,0x49b40821L,
0xf61e2562L,0xc040b340L,0x265e5a51L,0xe9b6c7aaL,0xd62f105dL,0x02441453L,0xd8a1e681L,0xe7d3fbc8L,
0x21e1cde6L,0xc33707d6L,0xf4d50d87L,0x455a14edL,0xa9e3e905L,0xfcefa3f8L,0x676f02d9L,0x8d2a4c8aL,
0xfffa3942L,0x8771f681L,0x6d9d6122L,0xfde5380cL,0xa4beea44L,0x4bdecfa9L,0xf6bb4b60L,0xbebfbc70L,
0x289b7ec6L,0xeaa127faL,0xd4ef3085L,0x4881d05L,0xd9d4d039L,0xe6db99e5L,0x1fa27cf8L,0xc4ac5665L,
0xf4292244L,0x432aff97L,0xab9423a7L,0xfc93a039L,0x655b59c3L,0x8f0ccc92L,0xffeff47dL,0x85845dd1L,
0x6fa87e4fL,0xfe2ce6e0L,0xa3014314L,0x4e0811a1L,0xf7537e82L,0xbd3af235L,0x2ad7d2bbL,0xeb86d391L};
第四步,计算:
首先定义四个基础运算并重新定义四个变量:
a=A,b=B,c=C,d=D
F(X,Y,Z)=(X&Y)|((~X)&Z)
G(X,Y,Z)=(X&Z)|(Y&(~Z))
H(X,Y,Z)=XYZ
I(X,Y,Z)=Y^(X|(~Z))
private static long F(long x, long y, long z) {
return (x & y) | ((~x) & z);
}
private static long G(long x, long y, long z) {
return (x & z) | (y & (~z));
}
private static long H(long x, long y, long z) {
return x ^ y ^ z;
}
private static long I(long x, long y, long z) {
return y ^ (x | (~z));
}
四轮大运算,每一轮运算包括16小轮,不断更新abcd的值
FF(a,b,c,d,Mj,s,ti)表示a=b+((a+F(b,c,d)+Mj+ti)<<<s)
GG(a,b,c,d,Mj,s,ti)表示a=b+((a+G(b,c,d)+Mj+ti)<<<s)
HH(a,b,c,d,Mj,s,ti)表示a=b+((a+H(b,c,d)+Mj+ti)<<<s)
II(a,b,c,d,Mj,s,ti)表示a=b+((a+I(b,c,d)+Mj+ti)<<<s)
/*第一轮*/
a = FF(a, b, c, d, groups[0], s[i++], t[j++]); /* 1 i=0*/
d = FF(d, a, b, c, groups[1], s[i++], t[j++]); /* 2 1*/
c = FF(c, d, a, b, groups[2], s[i++], t[j++]); /* 3 2*/
b = FF(b, c, d, a, groups[3], s[i++], t[j++]); /* 4 3*/
a = FF(a, b, c, d, groups[4], s[i++], t[j++]); /* 5 4*/
d = FF(d, a, b, c, groups[5], s[i++], t[j++]); /* 6 5*/
c = FF(c, d, a, b, groups[6], s[i++], t[j++]); /* 7 6*/
b = FF(b, c, d, a, groups[7], s[i++], t[j++]); /* 8 7*/
a = FF(a, b, c, d, groups[8], s[i++], t[j++]); /* 9 8*/
d = FF(d, a, b, c, groups[9], s[i++], t[j++]); /* 10 9 */
c = FF(c, d, a, b, groups[10], s[i++], t[j++]); /* 11 10*/
b = FF(b, c, d, a, groups[11], s[i++], t[j++]); /* 12 11*/
a = FF(a, b, c, d, groups[12], s[i++], t[j++]); /* 13 12*/
d = FF(d, a, b, c, groups[13], s[i++], t[j++]); /* 14 13*/
c = FF(c, d, a, b, groups[14], s[i++], t[j++]); /* 15 14*/
b = FF(b, c, d, a, groups[15], s[i++], t[j++]); /* 16 15*/
/*第二轮*/
a = GG(a, b, c, d, groups[1], s[i++], t[j++]); /* 17 */
d = GG(d, a, b, c, groups[6], s[i++], t[j++]); /* 18 */
c = GG(c, d, a, b, groups[11], s[i++], t[j++]); /* 19 */
b = GG(b, c, d, a, groups[0], s[i++], t[j++]); /* 20 */
a = GG(a, b, c, d, groups[5], s[i++], t[j++]); /* 21 */
d = GG(d, a, b, c, groups[10], s[i++], t[j++]); /* 22 */
c = GG(c, d, a, b, groups[15], s[i++], t[j++]); /* 23 */
b = GG(b, c, d, a, groups[4], s[i++], t[j++]); /* 24 */
a = GG(a, b, c, d, groups[9], s[i++], t[j++]); /* 25 */
d = GG(d, a, b, c, groups[14], s[i++], t[j++]); /* 26 */
c = GG(c, d, a, b, groups[3], s[i++], t[j++]); /* 27 */
b = GG(b, c, d, a, groups[8], s[i++], t[j++]); /* 28 */
a = GG(a, b, c, d, groups[13], s[i++], t[j++]); /* 29 */
d = GG(d, a, b, c, groups[2], s[i++], t[j++]); /* 30 */
c = GG(c, d, a, b, groups[7], s[i++], t[j++]); /* 31 */
b = GG(b, c, d, a, groups[12], s[i++], t[j++]); /* 32 */
/*第三轮*/
a = HH(a, b, c, d, groups[5], s[i++], t[j++]); /* 33 */
d = HH(d, a, b, c, groups[8], s[i++], t[j++]); /* 34 */
c = HH(c, d, a, b, groups[11], s[i++], t[j++]); /* 35 */
b = HH(b, c, d, a, groups[14], s[i++], t[j++]); /* 36 */
a = HH(a, b, c, d, groups[1], s[i++], t[j++]); /* 37 */
d = HH(d, a, b, c, groups[4], s[i++], t[j++]); /* 38 */
c = HH(c, d, a, b, groups[7], s[i++], t[j++]); /* 39 */
b = HH(b, c, d, a, groups[10], s[i++], t[j++]); /* 40 */
a = HH(a, b, c, d, groups[13], s[i++], t[j++]); /* 41 */
d = HH(d, a, b, c, groups[0], s[i++], t[j++]); /* 42 */
c = HH(c, d, a, b, groups[3], s[i++], t[j++]); /* 43 */
b = HH(b, c, d, a, groups[6], s[i++], t[j++]); /* 44 */
a = HH(a, b, c, d, groups[9], s[i++], t[j++]); /* 45 */
d = HH(d, a, b, c, groups[12], s[i++], t[j++]); /* 46 */
c = HH(c, d, a, b, groups[15], s[i++], t[j++]); /* 47 */
b = HH(b, c, d, a, groups[2], s[i++], t[j++]); /* 48 */
/*第四轮*/
a = II(a, b, c, d, groups[0], s[i++], t[j++]); /* 49 */
d = II(d, a, b, c, groups[7], s[i++], t[j++]); /* 50 */
c = II(c, d, a, b, groups[14], s[i++], t[j++]); /* 51 */
b = II(b, c, d, a, groups[5], s[i++], t[j++]); /* 52 */
a = II(a, b, c, d, groups[12], s[i++], t[j++]); /* 53 */
d = II(d, a, b, c, groups[3], s[i++], t[j++]); /* 54 */
c = II(c, d, a, b, groups[10], s[i++], t[j++]); /* 55 */
b = II(b, c, d, a, groups[1], s[i++], t[j++]); /* 56 */
a = II(a, b, c, d, groups[8], s[i++], t[j++]); /* 57 */
d = II(d, a, b, c, groups[15], s[i++], t[j++]); /* 58 */
c = II(c, d, a, b, groups[6], s[i++], t[j++]); /* 59 */
b = II(b, c, d, a, groups[13], s[i++], t[j++]); /* 60 */
a = II(a, b, c, d, groups[4], s[i++], t[j++]); /* 61 */
d = II(d, a, b, c, groups[11], s[i++], t[j++]); /* 62 */
c = II(c, d, a, b, groups[2], s[i++], t[j++]); /* 63 */
b = II(b, c, d, a, groups[9], s[i++], t[j++]); /* 64 */
运算完后,abcd获得了更新,然后赋值给ABCD;
A=A+a,B=b+B,C=c+C,D=d+D
第五步,输出
因为完成后,我们的结果还是小端存储的,即从左往右低地址->高地址,低字节->高字节
所以输出的时候需要从后往前输出,一直右移四位即可,并要十进制转十六进制。
代码实现
import java.util.Scanner;
public class md5 {
//存储应为小端存储
static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};
private static final long A=0x67452301L; //小端
private static final long B=0xefcdab89L;
private static final long C=0x98badcfeL;
private static final long D=0x10325476L;
//循环左移位数
static final 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
static final long t[]={
0xd76aa478L,0xe8c7b756L,0x242070dbL,0xc1bdceeeL,0xf57c0fafL,0x4787c62aL,0xa8304613L,0xfd469501L,
0x698098d8L,0x8b44f7afL,0xffff5bb1L,0x895cd7beL,0x6b901122L,0xfd987193L,0xa679438eL,0x49b40821L,
0xf61e2562L,0xc040b340L,0x265e5a51L,0xe9b6c7aaL,0xd62f105dL,0x02441453L,0xd8a1e681L,0xe7d3fbc8L,
0x21e1cde6L,0xc33707d6L,0xf4d50d87L,0x455a14edL,0xa9e3e905L,0xfcefa3f8L,0x676f02d9L,0x8d2a4c8aL,
0xfffa3942L,0x8771f681L,0x6d9d6122L,0xfde5380cL,0xa4beea44L,0x4bdecfa9L,0xf6bb4b60L,0xbebfbc70L,
0x289b7ec6L,0xeaa127faL,0xd4ef3085L,0x4881d05L,0xd9d4d039L,0xe6db99e5L,0x1fa27cf8L,0xc4ac5665L,
0xf4292244L,0x432aff97L,0xab9423a7L,0xfc93a039L,0x655b59c3L,0x8f0ccc92L,0xffeff47dL,0x85845dd1L,
0x6fa87e4fL,0xfe2ce6e0L,0xa3014314L,0x4e0811a1L,0xf7537e82L,0xbd3af235L,0x2ad7d2bbL,0xeb86d391L};
private long [] result={A,B,C,D};//存储hash结果,共4×32=128位
private String digest(String inputStr){
byte [] inputBytes=inputStr.getBytes(); //目前输入得到的为大端
int byteLen=inputBytes.length;//长度(字节)
long []groups=null;//每个小组(64字节)再细分后的16个小组(4字节)
//进行填充
int rest=byteLen%64;
byte [] tempBytes=new byte[64]; //512/8=64字节
for(int i=0;i<rest;i++)
tempBytes[i]=inputBytes[byteLen-rest+i];
if(rest<56){ //448/8=56
tempBytes[rest]=(byte)(1<<7);//使用1填充10000000
for(int i=1;i<56-rest;i++)
tempBytes[rest+i]=0;//剩下的使用0填充
}
long len=(long)(byteLen<<3);//5*8=40,得到消息长度
for(int i=0;i<8;i++){ //64-56=8,还剩下8个没有赋值
if(i==0){
tempBytes[56+i]=(byte)(len&0xFFL);
}
else
tempBytes[56+i]=0;
}
groups=divide_group(tempBytes);
xunhuan(groups);//处理分组
//将Hash值转换成十六进制的字符串(小端转大端) 低字节->高字节,所以从后往前输出
String str="";
long temp=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){ //[690955041, 2812630906, 239765827, 3273621578] 需要大小端转换,所以从后往前
temp=result[i]&0x0FL;//提取十进制的最后一位即二进制的后四位
String a=hexs[(int)(temp)];
result[i]=result[i]>>4; //最后一位已经拿出来,去掉,相当于除以16
temp=result[i]&0x0FL; //十进制转二进制最后四位
str+=hexs[(int)(temp)]+a;
result[i]=result[i]>>4; //再进行取出后四位操作
}
}
return str;
}
/**
* 从inputBytes的index开始取512位,作为新的分组
* 将每一个512位的分组再细分成16个小组
*/
private static long[] divide_group(byte[] inputBytes){
long [] temp=new long[16];
for(int i=0;i<16;i++){
temp[i]=www(inputBytes[4*i])|
(www(inputBytes[4*i+1]))<<8|
(www(inputBytes[4*i+2]))<<16|
(www(inputBytes[4*i+3]))<<24;//将他们扩大相应的倍数,转成小端
}
return temp;
}
//调整符号,全都变成正值
public static long www(byte b){
return b < 0 ? b & 0x7F + 128 : b;
}
/**
* 主要的操作,四轮循环
* @param groups[]--每一个分组512位(64字节)
*/
private void xunhuan(long[] groups) {
long a = result[0], b = result[1], c = result[2], d = result[3];
int i=0,j=0;
/*第一轮*/
a = FF(a, b, c, d, groups[0], s[i++], t[j++]); /* 1 i=0*/
d = FF(d, a, b, c, groups[1], s[i++], t[j++]); /* 2 1*/
c = FF(c, d, a, b, groups[2], s[i++], t[j++]); /* 3 2*/
b = FF(b, c, d, a, groups[3], s[i++], t[j++]); /* 4 3*/
a = FF(a, b, c, d, groups[4], s[i++], t[j++]); /* 5 4*/
d = FF(d, a, b, c, groups[5], s[i++], t[j++]); /* 6 5*/
c = FF(c, d, a, b, groups[6], s[i++], t[j++]); /* 7 6*/
b = FF(b, c, d, a, groups[7], s[i++], t[j++]); /* 8 7*/
a = FF(a, b, c, d, groups[8], s[i++], t[j++]); /* 9 8*/
d = FF(d, a, b, c, groups[9], s[i++], t[j++]); /* 10 9 */
c = FF(c, d, a, b, groups[10], s[i++], t[j++]); /* 11 10*/
b = FF(b, c, d, a, groups[11], s[i++], t[j++]); /* 12 11*/
a = FF(a, b, c, d, groups[12], s[i++], t[j++]); /* 13 12*/
d = FF(d, a, b, c, groups[13], s[i++], t[j++]); /* 14 13*/
c = FF(c, d, a, b, groups[14], s[i++], t[j++]); /* 15 14*/
b = FF(b, c, d, a, groups[15], s[i++], t[j++]); /* 16 15*/
/*第二轮*/
a = GG(a, b, c, d, groups[1], s[i++], t[j++]); /* 17 */
d = GG(d, a, b, c, groups[6], s[i++], t[j++]); /* 18 */
c = GG(c, d, a, b, groups[11], s[i++], t[j++]); /* 19 */
b = GG(b, c, d, a, groups[0], s[i++], t[j++]); /* 20 */
a = GG(a, b, c, d, groups[5], s[i++], t[j++]); /* 21 */
d = GG(d, a, b, c, groups[10], s[i++], t[j++]); /* 22 */
c = GG(c, d, a, b, groups[15], s[i++], t[j++]); /* 23 */
b = GG(b, c, d, a, groups[4], s[i++], t[j++]); /* 24 */
a = GG(a, b, c, d, groups[9], s[i++], t[j++]); /* 25 */
d = GG(d, a, b, c, groups[14], s[i++], t[j++]); /* 26 */
c = GG(c, d, a, b, groups[3], s[i++], t[j++]); /* 27 */
b = GG(b, c, d, a, groups[8], s[i++], t[j++]); /* 28 */
a = GG(a, b, c, d, groups[13], s[i++], t[j++]); /* 29 */
d = GG(d, a, b, c, groups[2], s[i++], t[j++]); /* 30 */
c = GG(c, d, a, b, groups[7], s[i++], t[j++]); /* 31 */
b = GG(b, c, d, a, groups[12], s[i++], t[j++]); /* 32 */
/*第三轮*/
a = HH(a, b, c, d, groups[5], s[i++], t[j++]); /* 33 */
d = HH(d, a, b, c, groups[8], s[i++], t[j++]); /* 34 */
c = HH(c, d, a, b, groups[11], s[i++], t[j++]); /* 35 */
b = HH(b, c, d, a, groups[14], s[i++], t[j++]); /* 36 */
a = HH(a, b, c, d, groups[1], s[i++], t[j++]); /* 37 */
d = HH(d, a, b, c, groups[4], s[i++], t[j++]); /* 38 */
c = HH(c, d, a, b, groups[7], s[i++], t[j++]); /* 39 */
b = HH(b, c, d, a, groups[10], s[i++], t[j++]); /* 40 */
a = HH(a, b, c, d, groups[13], s[i++], t[j++]); /* 41 */
d = HH(d, a, b, c, groups[0], s[i++], t[j++]); /* 42 */
c = HH(c, d, a, b, groups[3], s[i++], t[j++]); /* 43 */
b = HH(b, c, d, a, groups[6], s[i++], t[j++]); /* 44 */
a = HH(a, b, c, d, groups[9], s[i++], t[j++]); /* 45 */
d = HH(d, a, b, c, groups[12], s[i++], t[j++]); /* 46 */
c = HH(c, d, a, b, groups[15], s[i++], t[j++]); /* 47 */
b = HH(b, c, d, a, groups[2], s[i++], t[j++]); /* 48 */
/*第四轮*/
a = II(a, b, c, d, groups[0], s[i++], t[j++]); /* 49 */
d = II(d, a, b, c, groups[7], s[i++], t[j++]); /* 50 */
c = II(c, d, a, b, groups[14], s[i++], t[j++]); /* 51 */
b = II(b, c, d, a, groups[5], s[i++], t[j++]); /* 52 */
a = II(a, b, c, d, groups[12], s[i++], t[j++]); /* 53 */
d = II(d, a, b, c, groups[3], s[i++], t[j++]); /* 54 */
c = II(c, d, a, b, groups[10], s[i++], t[j++]); /* 55 */
b = II(b, c, d, a, groups[1], s[i++], t[j++]); /* 56 */
a = II(a, b, c, d, groups[8], s[i++], t[j++]); /* 57 */
d = II(d, a, b, c, groups[15], s[i++], t[j++]); /* 58 */
c = II(c, d, a, b, groups[6], s[i++], t[j++]); /* 59 */
b = II(b, c, d, a, groups[13], s[i++], t[j++]); /* 60 */
a = II(a, b, c, d, groups[4], s[i++], t[j++]); /* 61 */
d = II(d, a, b, c, groups[11], s[i++], t[j++]); /* 62 */
c = II(c, d, a, b, groups[2], s[i++], t[j++]); /* 63 */
b = II(b, c, d, a, groups[9], s[i++], t[j++]); /* 64 */
result[0] = (result[0] + a) & 0xFFFFFFFFL;
result[1] = (result[1] + b) & 0xFFFFFFFFL;
result[2] = (result[2] + c) & 0xFFFFFFFFL;
result[3] = (result[3] + d) & 0xFFFFFFFFL;
}
private static long F(long x, long y, long z) {
return (x & y) | ((~x) & z);
}
private static long G(long x, long y, long z) {
return (x & z) | (y & (~z));
}
private static long H(long x, long y, long z) {
return x ^ y ^ z;
}
private static long I(long x, long y, long z) {
return y ^ (x | (~z));
}
private static long FF(long a, long b, long c, long d, long x, long s,long t) {
a = a + (F(b, c, d)&0xFFFFFFFFL) + x + t;
a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a = a + b;
return (a&0xFFFFFFFFL);
}
private static long GG(long a, long b, long c, long d, long x, long s,long t) {
a = a + (G(b, c, d)&0xFFFFFFFFL) + x + t;
a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a = a + b;
return (a&0xFFFFFFFFL);
}
private static long HH(long a, long b, long c, long d, long x, long s,long t) {
a = a + (H(b, c, d)&0xFFFFFFFFL) + x + t;
a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a = a + b;
return (a&0xFFFFFFFFL);
}
private static long II(long a, long b, long c, long d, long x, long s,long t) {
a = a + (I(b, c, d)&0xFFFFFFFFL) + x + t;
a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a = a + b;
return (a&0xFFFFFFFFL);
}
public static void main(String []args){
md5 md=new md5();
@SuppressWarnings("resource")
Scanner sc=new Scanner(System.in);
System.out.println("请输入你要加密的数据:");
String str=sc.nextLine();
System.out.println(str+"的MD5密文为:"+md.digest(str));
}
}