目录
1.MD5简介;
2.MD5用途;
3.MD5工具类的实现;
4.MD5加密过程;
5. MD5特征分析;
1.MD5简介;
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
密码散列函数(Cryptographic hash function),又译为加密散列函数,是散列函数的一种。它被认为是一种单向函数,也就是说极其难以由散列函数输出的结果,回推输入的数据是什么。这样的单向函数被称为“现代密码学的驮马”。这种散列函数的输入数据,通常被称为消息(message),而它的输出结果,经常被称为消息摘要(message digest)或摘要(digest)。在信息安全中,有许多重要的应用,都使用了密码散列函数来实现,例如数字签名,消息认证码。
2.MD5用途;
MD5特点:用户传入一个明文的字符串,加密后得到一个密文!
3.MD5工具类的实现;
加盐方式:
//加盐方式 public static String EncoderPwdByMd5(String pwd) throws NoSuchAlgorithmException { // 1,获取信息摘要对象md5,利用其单例函数来获取 MessageDigest md5=MessageDigest.getInstance("MD5"); // 2,信息摘要对象md5是对字节数组进行摘要的,所以先获取字符串的字节数组 byte[] str_bytes=pwd.getBytes(); // 3,信息摘要对象对得到的字节数组进行摘要,得到摘要字节数组,返回的是byte[] - 字节数组,长度是16个字节 byte[] result = md5.digest(str_bytes); // 4,把摘要数组中的每一个字节转换成16进制,并拼在一起就得到了MD5值. StringBuffer sb = new StringBuffer(); // 把每一个byte 做一个与运算 0xff; for (byte b : result) { // 与运算,获取字节的低8位有效值 int number = b & 0xff;// 加盐 // 将整数转换成16进制 String str = Integer.toHexString(number); // 如果是1位的话,补0 if (str.length() == 1) { sb.append("0"); } // 把密文添加到缓存中 sb.append(str); } // 标准的md5加密后的结果 return sb.toString(); }
主函数测试:
public static void main(String[] args) throws NoSuchAlgorithmException { System.out.println("加密后的密码为:\n"+EncoderPwdByMd5("123fbuinnviuiwj265")); System.out.println("md5密文的位数:\n"+EncoderPwdByMd5("123").length()); }
运行结果:
普通方式:
//普通方式 public static String EncoderPwdByMd5_2(String pwd) throws NoSuchAlgorithmException { char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; // 1,获取MD5摘要算法的MessageDigest对象md5,利用其单例函数来获取MD5的对象 MessageDigest md5=MessageDigest.getInstance("MD5"); // 2,将密码先转换成字节数,使用指定的字节更新摘要 md5.update(pwd.getBytes()); // 3,获得密文 byte[] result = md5.digest(); // 4,把密文(字节数组)转换成十六进制的字符串形式,拼在一起就得到了MD5值 int j = result.length; char str[] = new char[j * 2]; int k = 0; for (int i = 0; i < j; i++) { byte byte0 = result[i]; str[k++] = hexDigits[byte0 >>> 4 & 0xf]; str[k++] = hexDigits[byte0 & 0xf]; } return new String(str); }
主函数测试:
public static void main(String[] args) throws NoSuchAlgorithmException { //System.out.println("加密后的密码为:\n"+EncoderPwdByMd5("123fbuinnviuiwj265")); //System.out.println("md5密文的位数:\n"+EncoderPwdByMd5("123").length()); System.out.println("加密后的密码为:\n"+EncoderPwdByMd5_2("123")); System.out.println("md5密文的位数:\n"+EncoderPwdByMd5("123").length()); }
运行结果:
4.MD5加密过程;
加密过程分为4步:
第1步:
//1,获取MD5摘要算法的MessageDigest类,利用其单例函数来获取对象md5 MessageDigest md5=MessageDigest.getInstance("MD5");
第2步:
/*2,信息摘要的方法md5.digest(),其中的参数和返回值都是byte[](字节数组)类型; 所以先要获取字符串的字节数组;*/ byte[] str_bytes=pwd.getBytes();
第3步:
/*3,信息摘要对象对得到的字节数组进行摘要,得到摘要字节数组,返回的是byte[] - 字节数组,长度是16个字节*/ byte[] result = md5.digest(str_bytes);
第4步:
// 4,把摘要数组中的每一个字节转换成16进制,并拼在一起就得到了MD5值 StringBuffer sb = new StringBuffer(); // 把每一个byte 做一个与运算 0xff; for (byte b : result) { // 与运算,获取字节的低8位有效值 int number = b & 0xff; // 将整数转换成16进制 String str = Integer.toHexString(number); // 如果是1位的话,补0 if (str.length() == 1) { sb.append("0"); } // 把密文添加到缓存中 sb.append(str); } // 标准的md5加密后的结果 return sb.toString();
5. MD5特征分析;
总体概括:
用户传入一个明文的字符串(可见),加密后得到一个密文(不可见)!
得到的散列值特点:
1,密文为128bit(16字节)的散列值,用于确保信息传输完整一致
2,长度固定,不管多长的字符串,加密后长度都是一样长;
3,不可逆,你明明知道密文和加密方式,你却无法反向计算出原密码,一般解密不了;
长度问题:
1,md5的长度,默认为128bit,也就是128个0和1的二进制串;
2,格式不太好,所以将二进制转成了16进制,每4个bit表示一个16进制,
3,所以128/4 = 32 换成16进制表示后,为32位了;
byte类型转换成int类型:
首先byte是1个字节,8bit;
int是4个字节,32bit;
当把一个低精度的数据类型转成一个高精度的数据类型时,必然会涉及到如何扩展位数的问题;
补符号位扩展,若为负数,高24位全部补1,转换成十进制则会出问题。
目的就是为了保证二进制数据的一致性。
第一,oxff默认为整形,二进制位最低8位是1111 1111,前面24位都是0;
第二,&运算: 如果2个bit都是1,则得1,否则得0;
第三,byte的8位和0xff进行&运算后,最低8位中,原来为1的还是1,原来为0的还是0,而0xff其他位都是0,所以&后仍然得0,