MD5算法实验
一、实验目的
编程实现MD5算法,深入理解MD5加密解密原理
二、实验所用仪器(或实验环境)
计算机科学与技术学院实验中心,可接入Internet网台式机44台。
三、实验基本原理及要求
1.实验原理
第一步:添加填充位,如果输入明文的长度(bit)对512求余的结果不等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0。填充完后,信息的长度为N*512+448(bit)
第二步:填充长度,在第一步结果之后再填充上原消息的长度,可用来进行的存储长度为64位。如果消息长度大于2^64,则只使用其低64位的值,即(消息长度 对 2^64取模)。在此步骤进行完毕后,最终消息长度就是N x 512+448+64=(N+1) x 512。
第三步,初始化缓冲区, 一个128bit的缓冲区可用于保存hash函数中间和最终结果。可表示为4个32bit的寄存器(A,B,C,D). 其中A=(01234567)16,B=(89ABCDEF)16,C=(FEDCBA98)16,D=(76543210)16。如果在程序中定义应该是 A=0X67452301L,B=0XEFCDAB89L,C=0X98BADCFEL,D=0X10325476L
第四步:循环处理数据
其中每一轮操作为
第五步,级联输出,给出MD5算法加密后的密文。
2.实验要求
明文自定义(例如,可以是一句英文名言名句),利用MD5算法对其加密,给出实验过程以及加密结果。
四、实验步骤及实验数据记录:(要有文字描述和必要截图)
1.算法说明
MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。
2.代码结构
3.具体实现步骤
(1)我们第一步要做的就是填充,如果输入信息的长度(bit)对512求余的结果 不等于448,就需要填充使得对512求余的结果等于448。填充的方法是填充一个1和n个0。填充完后,信息的长度就为N*512+448(bit);代码如下图所示:
(2)将输入信息的原始长度b(bit)表示成一个64-bit的数字,把它添加到上一步的结果后面(在32位的机器上,这64位将用2个字来表示并且低位在前)。当遇到b大于2^64这种极少的情况时,b的高位被截去,仅使用b的低64位。经过上面两步,数据就被填补成长度为512(bit)的倍数。也就是说,此时的数据长度是16个字(32byte)的整数倍。代码如下图所示:
(3)装入标准的幻数(四个整数),用一个四个字的缓冲器(A,B,C,D)来计算报文摘要,A,B,C,D分别是32位的寄存器,初始化使用的是十六进制表示的数字,注意低字节在前:
? word A: 01 23 45 67 ? word B: 89 ab cd ef ? word C: fe dc ba 98 ? word D: 76 54 32 10
(4)四轮循环运算:循环的次数是分组的个数(N+1)
① 定义4个辅助函数,每个函数的输入是三个32位的字,输出是一个32位的字:(&是与,|是或,~是非,^是异或),代码如下图所示:
? 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))
②设Mj表示消息的第j个子分组(从0到15):代码如下图所示:
? 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)
(5)每轮循环后,将A,B,C,D分别加上a,b,c,d,然后进入下一循环
五、实验结果分析
1.实验结果
开始我们传入的字符串为:“Embrace the glorious mess that you are”,最后得到的MD5值为“ADE90D3E14F9114D0EF4626971DE0BD0”。
2.实验总结
任何消息经过散列函数处理后,都会产生一个唯一的散列值,这个散列值可以用来验证消息的完整性,MD5也正是利用了这个特点,通过对MD5算法原理的学习及实验,我对散列函数压缩性、容易计算、抗修改性的特点有了更加深刻的体会,对于MD5算法的验证基本上只有借助计算机才可以进行,因为MD5算法在计算量上相对来说还是比较复杂的,通过计算机我们可以很简单的进行求和运算,当完成最后一个明文的分组运算时,A、B、C、D中的数值就是最后的结果(即散列函数值)。
六、开源地址
实验报告及代码开源地址(Github)
七、源代码
class MD5{
static final int S11 = 7;
static final int S12 = 12;
static final int S13 = 17;
static final int S14 = 22;
static final int S21 = 5;
static final int S22 = 9;
static final int S23 = 14;
static final int S24 = 20;
static final int S31 = 4;
static final int S32 = 11;
static final int S33 = 16;
static final int S34 = 23;
static final int S41 = 6;
static final int S42 = 10;
static final int S43 = 15;
static final int S44 = 21;
private static final long A=0x67452301L;
private static final long B=0xefcdab89L;
private static final long C=0x98badcfeL;
private static final long D=0x10325476L;
private long [] result={A,B,C,D};
static final String hexs[]={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
private String str;
public MD5(String str) {
this.str=str;
String result=Main_process();
System.out.println("| MD5---<"+str+">"+" | \nResult: "+result);
}
private String Main_process() {
byte [] inputBytes=str.getBytes();
int str_length=inputBytes.length;
int group_number=0;
group_number=str_length/64;
long []groups=null;
for(int i=0;i<group_number;i++){
groups=Create_NewGroup(inputBytes,i*64);
Transform(groups);
}
int rest=str_length%64;
byte [] tempBytes=new byte[64];
if(rest<=56){
for(int i=0;i<rest;i++)
tempBytes[i]=inputBytes[str_length-rest+i];
if(rest<56){
tempBytes[rest]=(byte)(1<<7);
for(int i=1;i<56-rest;i++)
tempBytes[rest+i]=0;
}
long len=(long)(str_length<<3);
for(int i=0;i<8;i++){
tempBytes[56+i]=(byte)(len&0xFFL);
len=len>>8;
}
groups=Create_NewGroup(tempBytes,0);
Transform(groups);
}else{
for(int i=0;i<rest;i++)
tempBytes[i]=inputBytes[str_length-rest+i];
tempBytes[rest]=(byte)(1<<7);
for(int i=rest+1;i<64;i++)
tempBytes[i]=0;
groups=Create_NewGroup(tempBytes,0);
Transform(groups);
for(int i=0;i<56;i++)
tempBytes[i]=0;
long len=(long)(str_length<<3);
for(int i=0;i<8;i++){
tempBytes[56+i]=(byte)(len&0xFFL);
len=len>>8;
}
groups=Create_NewGroup(tempBytes,0);
Transform(groups);
}
return ToHexString();
}
private String ToHexString(){
String resStr="";
long temp=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
temp=result[i]&0x0FL;
String a=hexs[(int)(temp)];
result[i]=result[i]>>4;
temp=result[i]&0x0FL;
resStr+=hexs[(int)(temp)]+a;
result[i]=result[i]>>4;
}
}
return resStr;
}
private void Transform(long[] groups) {
long a = result[0], b = result[1], c = result[2], d = result[3];
a = FF(a, b, c, d, groups[0], S11, 0xd76aa478L);
d = FF(d, a, b, c, groups[1], S12, 0xe8c7b756L);
c = FF(c, d, a, b, groups[2], S13, 0x242070dbL);
b = FF(b, c, d, a, groups[3], S14, 0xc1bdceeeL);
a = FF(a, b, c, d, groups[4], S11, 0xf57c0fafL);
d = FF(d, a, b, c, groups[5], S12, 0x4787c62aL);
c = FF(c, d, a, b, groups[6], S13, 0xa8304613L);
b = FF(b, c, d, a, groups[7], S14, 0xfd469501L);
a = FF(a, b, c, d, groups[8], S11, 0x698098d8L);
d = FF(d, a, b, c, groups[9], S12, 0x8b44f7afL);
c = FF(c, d, a, b, groups[10], S13, 0xffff5bb1L);
b = FF(b, c, d, a, groups[11], S14, 0x895cd7beL);
a = FF(a, b, c, d, groups[12], S11, 0x6b901122L);
d = FF(d, a, b, c, groups[13], S12, 0xfd987193L);
c = FF(c, d, a, b, groups[14], S13, 0xa679438eL);
b = FF(b, c, d, a, groups[15], S14, 0x49b40821L);
a = GG(a, b, c, d, groups[1], S21, 0xf61e2562L);
d = GG(d, a, b, c, groups[6], S22, 0xc040b340L);
c = GG(c, d, a, b, groups[11], S23, 0x265e5a51L);
b = GG(b, c, d, a, groups[0], S24, 0xe9b6c7aaL);
a = GG(a, b, c, d, groups[5], S21, 0xd62f105dL);
d = GG(d, a, b, c, groups[10], S22, 0x2441453L);
c = GG(c, d, a, b, groups[15], S23, 0xd8a1e681L);
b = GG(b, c, d, a, groups[4], S24, 0xe7d3fbc8L);
a = GG(a, b, c, d, groups[9], S21, 0x21e1cde6L);
d = GG(d, a, b, c, groups[14], S22, 0xc33707d6L);
c = GG(c, d, a, b, groups[3], S23, 0xf4d50d87L);
b = GG(b, c, d, a, groups[8], S24, 0x455a14edL);
a = GG(a, b, c, d, groups[13], S21, 0xa9e3e905L);
d = GG(d, a, b, c, groups[2], S22, 0xfcefa3f8L);
c = GG(c, d, a, b, groups[7], S23, 0x676f02d9L);
b = GG(b, c, d, a, groups[12], S24, 0x8d2a4c8aL);
a = HH(a, b, c, d, groups[5], S31, 0xfffa3942L);
d = HH(d, a, b, c, groups[8], S32, 0x8771f681L);
c = HH(c, d, a, b, groups[11], S33, 0x6d9d6122L);
b = HH(b, c, d, a, groups[14], S34, 0xfde5380cL);
a = HH(a, b, c, d, groups[1], S31, 0xa4beea44L);
d = HH(d, a, b, c, groups[4], S32, 0x4bdecfa9L);
c = HH(c, d, a, b, groups[7], S33, 0xf6bb4b60L);
b = HH(b, c, d, a, groups[10], S34, 0xbebfbc70L);
a = HH(a, b, c, d, groups[13], S31, 0x289b7ec6L);
d = HH(d, a, b, c, groups[0], S32, 0xeaa127faL);
c = HH(c, d, a, b, groups[3], S33, 0xd4ef3085L);
b = HH(b, c, d, a, groups[6], S34, 0x4881d05L);
a = HH(a, b, c, d, groups[9], S31, 0xd9d4d039L);
d = HH(d, a, b, c, groups[12], S32, 0xe6db99e5L);
c = HH(c, d, a, b, groups[15], S33, 0x1fa27cf8L);
b = HH(b, c, d, a, groups[2], S34, 0xc4ac5665L);
a = II(a, b, c, d, groups[0], S41, 0xf4292244L);
d = II(d, a, b, c, groups[7], S42, 0x432aff97L);
c = II(c, d, a, b, groups[14], S43, 0xab9423a7L);
b = II(b, c, d, a, groups[5], S44, 0xfc93a039L);
a = II(a, b, c, d, groups[12], S41, 0x655b59c3L);
d = II(d, a, b, c, groups[3], S42, 0x8f0ccc92L);
c = II(c, d, a, b, groups[10], S43, 0xffeff47dL);
b = II(b, c, d, a, groups[1], S44, 0x85845dd1L);
a = II(a, b, c, d, groups[8], S41, 0x6fa87e4fL);
d = II(d, a, b, c, groups[15], S42, 0xfe2ce6e0L);
c = II(c, d, a, b, groups[6], S43, 0xa3014314L);
b = II(b, c, d, a, groups[13], S44, 0x4e0811a1L);
a = II(a, b, c, d, groups[4], S41, 0xf7537e82L);
d = II(d, a, b, c, groups[11], S42, 0xbd3af235L);
c = II(c, d, a, b, groups[2], S43, 0x2ad7d2bbL);
b = II(b, c, d, a, groups[9], S44, 0xeb86d391L);
result[0] += a;
result[1] += b;
result[2] += c;
result[3] += d;
result[0]=result[0]&0xFFFFFFFFL;
result[1]=result[1]&0xFFFFFFFFL;
result[2]=result[2]&0xFFFFFFFFL;
result[3]=result[3]&0xFFFFFFFFL;
}
private long DealHi(byte b){
return b < 0 ? b & 0x7F + 128 : b;
}
private long[] Create_NewGroup(byte[] inputBytes,int index){
long [] temp=new long[16];
for(int i=0;i<16;i++){
temp[i]=DealHi(inputBytes[4*i+index])|
(DealHi(inputBytes[4*i+1+index]))<<8|
(DealHi(inputBytes[4*i+2+index]))<<16|
(DealHi(inputBytes[4*i+3+index]))<<24;
}
return temp;
}
private long F(long x, long y, long z) {
return (x & y) | ((~x) & z);
}
private 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 long I(long x, long y, long z) {
return y ^ (x | (~z));
}
private long FF(long a, long b, long c, long d, long x, long s,
long ac) {
a += (F(b, c, d)&0xFFFFFFFFL) + x + ac;
a = ((a&0xFFFFFFFFL)<< s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a += b;
return (a&0xFFFFFFFFL);
}
private long GG(long a, long b, long c, long d, long x, long s,
long ac) {
a += (G(b, c, d)&0xFFFFFFFFL) + x + ac;
a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a += b;
return (a&0xFFFFFFFFL);
}
private long HH(long a, long b, long c, long d, long x, long s,
long ac) {
a += (H(b, c, d)&0xFFFFFFFFL) + x + ac;
a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a += b;
return (a&0xFFFFFFFFL);
}
private long II(long a, long b, long c, long d, long x, long s,
long ac) {
a += (I(b, c, d)&0xFFFFFFFFL) + x + ac;
a = ((a&0xFFFFFFFFL) << s) | ((a&0xFFFFFFFFL) >>> (32 - s));
a += b;
return (a&0xFFFFFFFFL);
}
}
public class IOT_md5 {
public static void main(String []args){
String str="Embrace the glorious mess that you are";
MD5 md=new MD5(str);
}
}
|