消息摘要 —— MD5算法
2016-02-22 19:43
441 查看
消息摘要也叫Hash算法,它可以把不定长的输入数据转换为定长的输出数据,常见的Hash算法有
Hash算法的特点:
易变性:即使源数据发生
不可逆:通过摘要信息逆推出原数据是极其困难的。
主要的应用场景:
下载文件后为了保证文件的完整性,通常会校验附带的摘要信息,当网络环境恶劣时,也可以弥补CRC校验的不足。
手机登录密码验证时,通常对密码进行一次摘要计算,发送给服务端,服务端与后台数据库比对摘要信息,完成一次登录验证。这样即使数据库丢失也不会泄露用户的密码。
下面我们来用代码来实现MD5算法:
但是这里会有一个问题,我们先来看下以上代码得到的摘要信息:
和正确的摘要信息比对发现多了很多F,这是为什么呢?我们再看byte数组的数据:
可以发现只有负数转为十六进制会补F,当我们使用
为了避免这种隐式转换发生的异常,在传入
多出的来F问题解决了,但是上面得到的摘要信息其实还有一个问题,0呢!0呢!!别急,我们来看看
可以看到,这个方法是不会在前面补零的,这就导致了我们的结果丢失了所有的零,解决这个问题其实很简单,转换前做个判断即可:
输出结果:
这次总算对了!说了这么多,其实还有一个更简单的方法,但是就效率来说明显不如上面的:
最后给出完整的摘要算法,可以作为一个工具类使用:
题外话:网上有在线MD5破解工具,可以通过摘要计算出原文。其实这只是一个伪破解,网站后台有个包含大量MD5摘要的数据库,这些都是已经计算好的,逆推时逐条去对比数据库中的信息。还有有个叫彩虹表的东西,支持6个字符以下的逆推,大概有100G吧,9个字符的也有,但是貌似要收费。
MD5(128bit)和
SHA1(160bit)。
Hash算法的特点:
易变性:即使源数据发生
1bit的信息变化,输出的数据都会有不可预知的变化。
不可逆:通过摘要信息逆推出原数据是极其困难的。
主要的应用场景:
下载文件后为了保证文件的完整性,通常会校验附带的摘要信息,当网络环境恶劣时,也可以弥补CRC校验的不足。
手机登录密码验证时,通常对密码进行一次摘要计算,发送给服务端,服务端与后台数据库比对摘要信息,完成一次登录验证。这样即使数据库丢失也不会泄露用户的密码。
下面我们来用代码来实现MD5算法:
/** * 原文:123456 * 摘要信息:E1 0A DC 39 49 BA 59 AB BE 56 E0 57 F2 0F 88 3E */ public static String str2MD5(String src) { String src = "123456"; MessageDigest md5 = MessageDigest.getInstance("MD5"); // 得到长度为32的byte数组 byte[] md5Bytes= md5.digest(src.getBytes("UTF-8")); // 遍历byte数组,逐个转为十六进制数 StringBuilder builder = new StringBuilder(); for (byte b : md5Bytes) { builder.append(Integer.toHexString(b)); } }
但是这里会有一个问题,我们先来看下以上代码得到的摘要信息:
FFFFFFE1 A FFFFFFDC 39 49 FFFFFFBA 59 FFFFFFAB FFFFFFBE 56 FFFFFFE0 57 FFFFFFF2 F FFFFFF88 3E
和正确的摘要信息比对发现多了很多F,这是为什么呢?我们再看byte数组的数据:
-31 10 -36 57 73 -70 89 -85 -66 86 -32 87 -14 15 -120 62
可以发现只有负数转为十六进制会补F,当我们使用
Integer.toHexString(int i)时,传入一个
byte进去,这时候发生隐式转换(
byte转为
int),当
byte为负数时,转换时就会自动在高位补
24bit的1,也就是多出来的六个F。
为了避免这种隐式转换发生的异常,在传入
byte时把这个数和
0xFF进行与运算,手动将1个字节的
byte扩展为4个字节的
int数据:
for (byte b : md5Bytes) { builder.append(Integer.toHexString(b & 0xFF)); }
多出的来F问题解决了,但是上面得到的摘要信息其实还有一个问题,0呢!0呢!!别急,我们来看看
Integer.toHexString(int i)的源码:
final static char[] digits = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' , 'v' , 'w' , 'x' , 'y' , 'z' }; public static String toHexString(int i) { return toUnsignedString(i, 4); } /** * 第二个参数代表进制:1(二进制)、3(八进制)、4(十六进制) */ private static String toUnsignedString(int i, int shift) { char[] buf = new char[32]; int charPos = 32; int radix = 1 << shift; // 16 int mask = radix - 1; /** * 假设i = 23,23 & 15 = 7(10111 & 01111 = 0111),查表得到7 * 然后右移运算:23 >>> 4 = 1(10111 >>> 4 = 1),进入下次循环查表得到1,组合起来就17 * 当i为0时就退出循环了,最后根据十六进制数的长度返回对应的字符串 */ do { buf[--charPos] = digits[i & mask]; i >>>= shift; } while (i != 0); return new String(buf, charPos, (32 - charPos)); }
可以看到,这个方法是不会在前面补零的,这就导致了我们的结果丢失了所有的零,解决这个问题其实很简单,转换前做个判断即可:
for (byte b : md5Bytes) { if ((b & 0xFF) < 0x10) builder.append("0"); // 当这个数小于16时则在前补零 builder.append(Integer.toHexString(b & 0xFF)); }
输出结果:
E1 0A DC 39 49 BA 59 AB BE 56 E0 57 F2 0F 88 3E
这次总算对了!说了这么多,其实还有一个更简单的方法,但是就效率来说明显不如上面的:
for (byte b : md5Bytes) { builder.append(String.format("%02x", b)); }
最后给出完整的摘要算法,可以作为一个工具类使用:
public class MD5Utils { public static String str2MD5(String src) { byte[] hash; try { hash = MessageDigest.getInstance("MD5").digest(src.getBytes("UTF-8")); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); return null; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } StringBuilder hex = new StringBuilder(); for (byte b : hash) { if ((b & 0xFF) < 0x10) hex.append("0"); hex.append(Integer.toHexString(b & 0xFF)); } return hex.toString().toUpperCase(); } }
题外话:网上有在线MD5破解工具,可以通过摘要计算出原文。其实这只是一个伪破解,网站后台有个包含大量MD5摘要的数据库,这些都是已经计算好的,逆推时逐条去对比数据库中的信息。还有有个叫彩虹表的东西,支持6个字符以下的逆推,大概有100G吧,9个字符的也有,但是貌似要收费。
相关文章推荐
- asp MD5加密方式使用建议
- 浅谈C#中Md5和Sha1两种加密方式
- 基于C#对用户密码使用MD5加密与解密
- Linux系统递归生成目录中文件的md5的方法
- 在C#中生成与PHP一样的MD5 Hash Code的方法
- asp.net实现md5加密
- Java Web开发之MD5加密用法分析
- C#计算字符串哈希值(MD5、SHA)的方法小结
- php 的加密函数 md5,crypt,base64_encode 等使用介绍
- PHP中MD5函数使用实例代码
- php md5下16位和32位的实现代码
- jquery插件开发之实现md5插件
- python基础教程之python消息摘要算法使用示例
- Java实现MD5加密的方法
- C#计算文件MD5校验的方法
- javascript实现base64 md5 sha1 密码加密
- 分享JavaScript与Java中MD5使用两个例子
- javascript客户端生成MD5值的函数代码
- c++实现MD5算法实现代码
- php验证是否是md5编码的简单代码