MD5

==下午老师给了个实验,很多个知识点,下个周三验收。我也就只能看看加密算法这块了。

作用:用于大容量信息,使其再用数字签名 (【数字证书】【数字签名】)软件签署私人秘钥前被“压缩”成一种保密格式,(就是把一个任意长的度的字节串,变换成一定长的大整数(128二进制位的信息摘要,这就是MD5为什么是不可逆的原因了(摘要得到的消息是不完整的),没有相对应的算法,由这个摘要还原成对应信息)
:可是这个MD5现在被山大王小云教授的团队在04年给破解了.


算法描述:以512位分组(DM5被分成了4组)的方式处理输入信息,而且每一个分组又被转化为16个32位子分组,经过处理后,输出由4个32位分组组成。最终这4个32位分组级联后最终生成一个128位散列值。

产生信息摘要具体过程:
0. 消息填充: 首先对信息进行填充(对原信息进行填充),使字节长度对512取余的结果等于448.此时信息的长度被扩展到n*512+448bits(即n*64+65个bytes,)
填充:在信息后面填充一个1和若干个0,直到满足上面的取余结果就可以停止填充.最后在后面附加一个填充前的信息长度(且是用64位的二进制表示的形式)
这样,信息的长度就变成了n*512+448+64=(n+1)*512bits.正好是512的整数倍。

1.初始化变量:MD5中有4个32位的整数参数(abcd),叫做链接变量。每一个参数都是被初始化为用16进制表示的形式:
a=0x01234567     b=0x89abcdef    c=0xfedcba98     d=0x76543210 

2.消息处理:在设置好链接变量之后就是循环,循环的次数和信息中512位信息分组的数目相等.所以算法中主循环就有了4次。每一次循环的结构都是相近的,区别在于使用的逻辑函数不同。
下面是逻辑函数(每一次循环依次用对应的一个):
F(x,y,z)=(x&y)|((~x)&z) 
G(x,y,z)=(x&z)|(y&(~z)) 
H(x,y,z)=x^y^z
I(x,y,z)=y^(x|(~z)) 

第一次主循环有16次操作,
每次操作对a、b、c、d中的三个变量做一次非线性函数运算,
在把所得的值加上第四个变量的值、加上文本的一个子分组(设Mj表示消息的第j个子分组0<=j<=15)、加上一个常数(设为ti,ti是4294967296*abs(sin(i))的整数部分,i的单位是弧度),在把新结果循环右移一个不定的数(设为s位),最后在加上abcd中的一个;
用这个最终的结果取代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) 
那么四次(共64步操作)循环就可以表示成下面的:(最终在所有的512位分组处理完之后,最后一个分组输出的就是级联后的128位的消息摘要)
第一次:
FF(a,b,c,d,M0,7,0xd76aa478) 
FF(d,a,b,c,M1,12,0xe8c7b756) 
FF(c,d,a,b,M2,17,0x242070db) 
FF(b,c,d,a,M3,22,0xc1bdceee) 
FF(a,b,c,d,M4,7,0xf57c0faf) 
FF(d,a,b,c,M5,12,0x4787c62a) 
FF(c,d,a,b,M6,17,0xa8304613) 
FF(b,c,d,a,M7,22,0xfd469501) 
FF(a,b,c,d,M8,7,0x698098d8) 
FF(d,a,b,c,M9,12,0x8b44f7af) 
FF(c,d,a,b,M10,17,0xffff5bb1) 
FF(b,c,d,a,M11,22,0x895cd7be) 
FF(a,b,c,d,M12,7,0x6b901122) 
FF(d,a,b,c,M13,12,0xfd987193) 
FF(c,d,a,b,M14,17,0xa679438e) 
FF(b,c,d,a,M15,22,0x49b40821) 
第二次:
GG(a,b,c,d,M1,5,0xf61e2562) 
GG(d,a,b,c,M6,9,0xc040b340) 
GG(c,d,a,b,M11,14,0x265e5a51) 
GG(b,c,d,a,M0,20,0xe9b6c7aa) 
GG(a,b,c,d,M5,5,0xd62f105d) 
GG(d,a,b,c,M10,9,0x02441453) 
GG(c,d,a,b,M15,14,0xd8a1e681) 
GG(b,c,d,a,M4,20,0xe7d3fbc8) 
GG(a,b,c,d,M9,5,0x21e1cde6) 
GG(d,a,b,c,M14,9,0xc33707d6) 
GG(c,d,a,b,M3,14,0xf4d50d87) 
GG(b,c,d,a,M8,20,0x455a14ed) 
GG(a,b,c,d,M13,5,0xa9e3e905) 
GG(d,a,b,c,M2,9,0xfcefa3f8) 
GG(c,d,a,b,M7,14,0x676f02d9) 
GG(b,c,d,a,M12,20,0x8d2a4c8a) 
第三次:
HH(a,b,c,d,M5,4,0xfffa3942) 
HH(d,a,b,c,M8,11,0x8771f681) 
HH(c,d,a,b,M11,16,0x6d9d6122) 
HH(b,c,d,a,M14,23,0xfde5380c) 
HH(a,b,c,d,M1,4,0xa4beea44) 
HH(d,a,b,c,M4,11,0x4bdecfa9) 
HH(c,d,a,b,M7,16,0xf6bb4b60) 
HH(b,c,d,a,M10,23,0xbebfbc70) 
HH(a,b,c,d,M13,4,0x289b7ec6) 
HH(d,a,b,c,M0,11,0xeaa127fa) 
HH(c,d,a,b,M3,16,0xd4ef3085) 
HH(b,c,d,a,M6,23,0x04881d05) 
HH(a,b,c,d,M9,4,0xd9d4d039) 
HH(d,a,b,c,M12,11,0xe6db99e5) 
HH(c,d,a,b,M15,16,0x1fa27cf8) 
HH(b,c,d,a,M2,23,0xc4ac5665) 
第四次:
II(a,b,c,d,M0,6,0xf4292244) 
II(d,a,b,c,M7,10,0x432aff97) 
II(c,d,a,b,M14,15,0xab9423a7) 
II(b,c,d,a,M5,21,0xfc93a039) 
II(a,b,c,d,M12,6,0x655b59c3) 
II(d,a,b,c,M3,10,0x8f0ccc92) 
II(c,d,a,b,M10,15,0xffeff47d) 
II(b,c,d,a,M1,21,0x85845dd1) 
II(a,b,c,d,M8,6,0x6fa87e4f) 
II(d,a,b,c,M15,10,0xfe2ce6e0) 
II(c,d,a,b,M6,15,0xa3014314) 
II(b,c,d,a,M13,21,0x4e0811a1) 
II(a,b,c,d,M4,6,0xf7537e82) 
II(d,a,b,c,M11,10,0xbd3af235) 
II(c,d,a,b,M2,15,0x2ad7d2bb) 
II(b,c,d,a,M9,21,0xeb86d391
 

Java 有jdk有自带的数据加密类 MessageDigest(对MD5、SHA加密)
【引字】
MessageDigest 通过其getInstance系列静态函数来进行实例化和初始化。MessageDigest 对象通过使用 update 方法处理数据。任何时候都可以调用 reset 方法重置摘要。一旦所有需要更新的数据都已经被更新了,应该调用 digest 方法之一完成哈希计算并返回结果。对于给定数量的更新数据,digest 方法只能被调用一次。digest 方法被调用后,MessageDigest  对象被重新设置成其初始状态。

MessageDigest 的实现可随意选择是否实现 Cloneable 接口。客户端应用程可以通过尝试复制和捕获 CloneNotSupportedException 测试可复制性:

MessageDigest md = MessageDigest.getInstance("SHA");

 try {

     md.update(toChapter1);

     MessageDigest tc1 = md.clone();

     byte[] toChapter1Digest = tc1.digest();

     md.update(toChapter2);

   //  ...etc.

 } catch (CloneNotSupportedException cnse) {

     throw new DigestException("couldn't make digest of partial content");

 }

注意1:即时给定MessageDigest的实现是不可复制的,则仍然能够通过getInstance方法实例化几个实例计算来同时进行摘要信息的计算。

注意2:由于历史原因,此类是抽象的,是从 MessageDigestSpi 扩展的。应用程序开发人员只应该注意在此 MessageDigest 类中定义的方法;超类中的所有方法是供希望提供自己的信息摘要算法实现的加密服务提供者使用的。 

注意3:MessageDigest并不是单实例的。如下代码所示:

try{

      MessageDigest mdTemp1 = MessageDigest.getInstance("MD5");
      MessageDigest mdTemp2= MessageDigest.getInstance("MD5");
      MessageDigest mdTemp3= MessageDigest.getInstance("MD5");
          System.out.println("mdTemp1==mdTemp2?:"+(mdTemp1==mdTemp2));
          System.out.println("mdTemp2==mdTemp3?:"+(mdTemp2==mdTemp3));
    }
 catch (NoSuchAlgorithmException e){
                // TODO Auto-generated catch block
                e.printStackTrace();
  }
//运行结果
//mdTemp1==mdTemp2?:false
//mdTemp2==mdTemp3?:false
//构造方法摘要:
protected MessageDigest(String algorithm)  //创建具有指定算法名称的MessageDigest实例对象。
//方法摘要
 Object 	clone()    //如果实现是可复制的,则返回一个副本。
 byte[] 	digest()   //通过执行诸如填充之类的最终操作完成哈希计算。
 byte[]    digest(byte[] input) //使用指定的字节数组对摘要进行最后更新,然后完成摘要计算。
 int  digest(byte[] buf, int offset,int len)  //通过执行诸如填充之类的最终操作完成哈希计算。
 String   getAlgorithm()   //返回标识算法的独立于实现细节的字符串。
int getDigestLength()
      //返回以字节为单位的摘要长度,如果提供程序不支持此操作并且实现是不可复制的,则返回 0。
static MessageDigest getInstance(String algorithm) 
      //生成实现指定摘要算法的 MessageDigest 对象。
static MessageDigest getInstance(String algorithm, Provider provider) 
      //生成实现指定提供程序提供的指定算法的 MessageDigest 对象,如果该算法可从指定的提供程                                   序得到的话。
static MessageDigest 	getInstance(String algorithm, String provider) 
       //生成实现指定提供程序提供的指定算法的 MessageDigest 对象,如果该算法可从指定的提供程序得到的话  
Provider getProvider()    // 返回此信息摘要对象的提供程序。
static boolean 	isEqual(byte[] digesta, byte[] digestb)     // 比较两个摘要的相等性。
void reset()       //重置摘要以供再次使用。
String 	toString()     //返回此信息摘要对象的字符串表示形式。
 void update(byte input)      // 使用指定的字节更新摘要。
 void update(byte[] input)    // 使用指定的字节数组更新摘要。
void update(byte[] input,int offset,int len) ///使用指定的字节数组,从指定偏移量开始更新摘要
 void update(ByteBuffer input)    //使用指定的 ByteBuffer 更新摘要。

方法说明:
 

/*
实际实践
2.1、创建 MessageDigest 对象
计算信息摘(即散列码)要做的第一步是创建 MessageDigest对象 实例。像所有的引擎类一样,获取某类报文摘要算法(即散列算法,比如MD5)的  MessageDigest 对象的途径是调用 MessageDigest 类中的 getInstance 静态 factory 方法:
*/
    public static MessageDigest getInstance(String algorithm)
//注意:算法名不区分大小写。例如,以下所有调用都是相等的:

MessageDigest.getInstance("SHA");
MessageDigest.getInstance("sha");
MessageDigest.getInstance("sHa");

//调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:

public static MessageDigest getInstance(String algorithm, String provider);
//调用 getInstance 将返回已初始化过的MessageDigest对象。因此,它不需要进一步的初始化。
/*
2.2、向MessageDigest传送要计算的数据
计算数据的摘要的第二步是向已初始化的MessageDigest对象提供传送要计算的数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:
*/
public void update(byte input);
public void update(byte[] input);
public void update(byte[] input, int offset, int len);

/*
2.3、计算摘要
通过调用 update 方法向MessageDigest对象提传送要计算的数据后,你就可以调用以下某个 digest(摘要)方法来计算摘要(即生成散列码):
*/
public byte[] digest();
public byte[] digest(byte[] input);
public int digest(byte[] buf, int offset, int len);

/*
前两个方法返回计算出的摘要。后一个方法把计算出的摘要储存在所提供的 buf 缓冲区中,起点是 offset。len 是 buf 中分配给该摘要的字节数。该方法返回实际存储在 buf 中的字节数。
对第二个接受输入字节数组变量的 digest 方法的调用等价于用指定的输入调用:
*/
    public void update(byte[] input)
,接着调用不带参数的 digest 方法.

栗子:
 

/*
java.security包中的MessageDigest类提供了计算消息摘要(即生成散列码)的方法,首先生成对象,执行其update( )方法可
以将原始数据传递给该对象,然后执行其digest( )方法即可得到消息摘要。具体步骤如下:
(1)生成MessageDigest对象
*/
MessageDigest m=MessageDigest.getInstance("MD5");
//MessageDigest类也是一个工厂类,其构造器是受保护的,不允许
/*
直接使用new MessageDigist( )来创建对象,而必须通过其静态方法getInstance( )生成MessageDigest对象。
其中传入的参数指定计算消息摘要所使用的算法,常用的有"MD5","SHA"等。
(2)传入需要计算的字符串
*/
m.update(x.getBytes("UTF8" ));
/*
分析:x为需要计算的字符串,update传入的参数是字节类型或字节类型数组,对于字符串,需要先使用getBytes( )方法生成字符串数组。
(3)计算消息摘要
*/
byte s[ ]=m.digest( );
/*
分析:执行MessageDigest对象的digest( )方法完成计算,计算的结果通过字节类型的数组返回。
(4)处理计算结果
必要的话可以使用如下代码将计算结果(byte数组)转换为字符串。
*/
static String convertToHexString(byte data[]) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
strBuffer.append(Integer.toHexString(0xff & data[i]));
}
return strBuffer.toString();
}

完整代码:
 

public class MessageDigestDemo extends Thread {
public void run() {
String text = "abc";
byte data[] = null;
MessageDigest m;
try {
data = text.getBytes("UTF8");
m = MessageDigest.getInstance("MD5");
m.update(data);
byte resultData[] = m.digest();
System.out.println(convertToHexString(resultData));
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
static String convertToHexString(byte data[]) {
StringBuffer strBuffer = new StringBuffer();
for (int i = 0; i < data.length; i++) {
strBuffer.append(Integer.toHexString(0xff & data[i]));
}
return strBuffer.toString();
}
}
/*
★运行结果
900150983cd24fb0d6963f7d28e17f72
 3.3、示例二
在这里我们将对计算生成的md5使用 sun.misc.BASE64Encoder进行简单的加密。
*/
    public String md5sumWithEncoder(String text) throws NoSuchAlgorithmException, 
UnsupportedEncodingException{
        /*确定计算方法*/
        MessageDigest md5=MessageDigest.getInstance("MD5");
        BASE64Encoder base64en = new BASE64Encoder();
        /*加密后的散列码字符串*/
        String strMd5=base64en.encode(md5.digest(text.getBytes("utf-8")));
        return strMd5;
    }

//调用函数

String str="0123456789"
 System.out.println(md5sumWithEncoder(str));

 //输出
eB5eJF1ptWaXm4bijSPyxw==
/*3.4、示例三
关于此请参考
《一点关于计算MD5的封装》:http://hubingforever.blog.163.com/blog/static/1710405792012112363345634/
*/

    两个例子: 0、   1       
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值