理解MD5
MD5的应用非常广泛h5棋牌源码租用(h5.hxforum.com)联系170618633533企鹅2952777280(http://yhgj8004.com)源码出售 房卡出售 后台出租联系方式只有企鹅。例如我们在unix中下载某种软件时,常常会看到一个扩展名为.md5的文件,内容大概是:
MD5 (tanajiya.tar.gz) = 0ca175b9c0f726a831d895e269332461
这就是tanajiya.tar.gz文件的数字签名。因此当我们得到这个文件后,使用工具计算该文件对应的md5值,然后和文件中记录的.md5中记录的值进行对比,如果不一致,就可以得知文件内容发生了变化。
MD5算法将整个文件当作一个大文本信息,通过其不可逆的字符串变换算法,产生了这个唯一的MD5信息摘要。这就相当于这个文件的指纹,如果有任何人修改了文件内容,或下载文件由于网络问题不完整,则生成的md5值也会发生变化。
MD5算法本质是一个哈希算法,因此MD5值就是一个哈希值。由这个例子可以得知MD5的一些特点:
1,对于同样的文件,计算出的MD5值永远是一样的。MD5算法中没有任何随机数或不确定因素。
2,MD5算法是公开的。因而我们可以找到很多个MD5生成器,但背后的算法是一样的。
3,我们可以认为世界上的文件是无限的,而得到的MD5值永远是一个128位二进制数。因此是一个无穷序列到一个有限序列的映射。进而可以得知,MD5算法是不可逆的,也就是说,我们不能用一个MD5值来推算出源文件的内容。
4,从无穷序列到有限序列的映射这点又可以推断出,MD5算法可能产生冲突(这也是所有哈希函数都会遇到的问题)。即两个不同的文件,可能会产生一样的MD5值。我们知道2^128次方是个巨大无比的数字,因此之前认为MD5的冲突在理论上存在,现实生活中遇到的可能性很低,因此是个可靠的算法。然而近年研究出的碰撞算法使得计算机在很短的时间内就可以得出一个可能的冲突值,这就是MD5算法的缺陷。我们在后面会提到这种缺陷的危害。
MD5的其它应用
数字证书
和前面的例子一样,在发行软件的时候,附带一个MD5证书。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。
安全认证
MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方面。如在UNⅨ系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。如果用户丢失了密码,只能让管理员重置密码。
MD5的缺陷
前面提到MD5的破解算法,也称为碰撞算法。本质就是对于一个给定的MD5,在很短的时间内就能找到可能的源文件内容。前面提到MD5算法是不可逆的,也就是说破解算法不能保证得到的一定是源文件内容,但是能保证该文件内容计算出的MD5值一定和源文件产生的MD5相同。我们来看看这有什么危害:比如用户的登录密码为666666,后台数据库存储的是MD5值,假如是0ca175b9c0f726a831d895e269332461。破解的人拿到这个MD5值,使用破解算法计算出和这个MD5碰撞的密码,假如是678865。
这样破解的人就可以使用678865去登录,由于MD5的输出还是0ca175b9c0f726a831d895e269332461,因此这个人就可以顺利登录。
对于这个问题,一个很容易的解决方案是,将用户输入的初始密码复制一份,变成666666666666,然后产生MD5,存入数据库。这样破解算法得到的可能的密码就不再是678865了,他也无法用这个可能密码去登录。
除了碰撞算法破解以外,现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字典"的暴力破解方法(brute force)。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 Bytes),同时密码只能是字母和数字,共26+26+10=62个字符,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的磁盘阵列,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。这种加密技术被广泛的应用于UNⅨ系统中,这也是为什么UNⅨ系统比一般操作系统更为坚固一个重要原因。
简单MD5类
[java] view plain copy
import java.security.MessageDigest;
public class MD5Demo {
public static class MD5_test {
public final static String MD5(String s) {
char hexDigits[] = { ‘0‘ , ‘1‘ , ‘2‘ , ‘3‘ , ‘4‘ , ‘5‘ , ‘6‘ , ‘7‘ , ‘8‘ , ‘9‘ ,
‘a‘ , ‘b‘ , ‘c‘ , ‘d‘ , ‘e‘ , ‘f‘ };
try {
byte [] strTemp = s.getBytes();
MessageDigest mdTemp = MessageDigest.getInstance("MD5" );
mdTemp.update(strTemp);
byte [] md = mdTemp.digest();
int j = md.length;
char str[] = new char [j * 2 ];
int k = 0 ;
for ( int i = 0 ; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf ];
str[k++] = hexDigits[byte0 & 0xf ];
}
return new String(str);
} catch (Exception e) {
return null ;
}
}
public static void main(String[] args) {
// MD5_test aa = new MD5_test();
System.out.print(MD5_test.MD5("b" ));
}
}
}
加密----------解密 MD5类
[java] view plain copy
import java.security.MessageDigest;
public class MD5andKL {
// MD5加码。32位
public static String MD5(String inStr) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
}
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
// 可逆的加密算法
public static String KL(String inStr) {
// String s = new String(inStr);
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ ‘t‘);
}
String s = new String(a);
return s;
}
// 加密后解密
public static String JM(String inStr) {
char[] a = inStr.toCharArray();
for (int i = 0; i < a.length; i++) {
a[i] = (char) (a[i] ^ ‘t‘);
}
String k = new String(a);
return k;
}
// 测试主函数
public static void main(String args[]) {
String s = new String("a");
System.out.println("原始:" + s);
System.out.println("MD5后:" + MD5(s));
System.out.println("MD5后再加密:" + KL(MD5(s)));
System.out.println("解密为MD5后的:" + JM(KL(MD5(s))));
}
}
原文地址:http://blog.51cto.com/13585417/2064704