哈希算法概述
哈希算法又称摘要算法,它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。哈希算法的目的:为了验证原始数据是否被篡改。
哈希算法的特点就是:
1.相同的输入一定得到相同的输出;
2.不同的输入大概率得到不同的输出。
常见的哈希算法:
算法输出长度(位)输出长度(字节)MD5128bit16bytesSHA-1160bit20bytesRipeMD-160160bit20bytesSHA-256256bit32bytesSHA-512512bit64bytes
Java标准库提供了常用的哈希算法,并且有一套统一的接口。以MD5算法为例,看看如何对输入计算哈希:
MD5算法
public static void main(String[] args) throws IOException {
try {
//获取一个MessageDigest对象:
MessageDigest digest = MessageDigest.getInstance("MD5");
//把要加密的内容转换成字节数据
byte[] simpledata = "hnczjtyrbl".getBytes();
System.out.println("原始数据:"+Arrays.toString(simpledata));
digest.update(simpledata);
//获得加密后的数据:
byte[] result = digest.digest();
System.out.println("加密后的数据:"+Arrays.toString(result));
//转换成十六进制的字符串
StringBuilder sb = new StringBuilder();
for(byte b:result) {
sb.append(String.format("%x", b));
}
System.out.println("转换成16进制字符串:"+sb);
System.out.println("长度:"+sb.length());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
MD5算法先获得一个MessageDigest对象,然后用update()方法传入要加密内容的字节数组。然后通过digest()方法获得最终加密的结果。
SHA-1算法:
SHA-1算法和MD5算法用法类似,不同的一点就是MD5加密的结果是一个长度为16的字节数组,而SHA-1加密的结果是一个长度为20的字节数组。
public static void main(String[] args) throws IOException {
try {// 要加密的内容
String password = "hdljdylzsx";
// 创建一个MessageDigest对象:
MessageDigest digest1 = MessageDigest.getInstance("SHA-1");
// 更新要加密的数据
digest1.update(password.getBytes());
byte[] resultArray1 = digest1.digest();
System.out.println("原始数据:" + Arrays.toString(password.getBytes()));
// 加密后的结果
System.out.println("加密后的结果:" + Arrays.toString(resultArray1));
System.out.println("长度:" + resultArray1.length);
StringBuilder sb = new StringBuilder();
for (byte b : resultArray1) {
sb.append(String.format("%x", b));
}
System.out.println("转换成16进制字符串:" + sb);
System.out.println("长度:" + sb.length());
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
哈希算法的用途
校验下载文件
因为相同的输入永远会的到相同的输出,因此,如果输入被修改了,得到的输出就会不同。我们在网站上下载软件的时候,经常会看到下载页显示MD5哈希值:
不存储用户的原始口令,那么如何对用户进行认证?方法是存储用户口令的哈希,例如,MD5。在用户输入原始口令后,系统计算用户输入的原始口令的MD5并与数据库存储的MD5对比,如果一致,说明口令正确,否则,口令错误。
如何判断下载到本地的软件是原始的、未经篡改的文件?我们只需要自己计算一下本地文件的哈希值,再与官网公开的哈希值对比,如果相同,说明文件下载正确,否则,说明文件已被篡改。
存储用户密码
哈希算法的另一个重要用途是存储用户口令。如果直接将用户的原始口令存放到数据库中,会产生极大的安全风险:
1.数据库管理员能够看到用户明文口令;
2.数据库数据一旦泄漏,黑客即可获取用户明文口令。
使用哈希口令时,还要注意防止彩虹表攻击。什么是彩虹表呢?上面讲到了,如果只拿到MD5,从MD5反推明文口令,只能使用暴力穷举的方法。然而黑客并不笨,暴力穷举会消耗大量的算力和时间。但是,如果有一个预先计算好的常用口令和它们的MD5的对照表,这个表就是彩虹表。如果用户使用了常用口令,黑客从MD5一下就能反查到原始口令:
当然,我们也可以采取特殊措施来抵御彩虹表攻击:对每个口令额外添加随机数,这个方法称之为“加盐”。这样即使数据库泄露,黑客也不能获得用户明文。
Hmac MD5算法
public static void main(String[] args) {
String password = "yyzsbjr";
try {
// 生成秘钥
// 秘钥生成器keyGenerator
KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
//生成秘钥key
SecretKey key = keyGen.generateKey();
byte[] keyByteArray = key.getEncoded();
System.out.println("秘钥长度" + keyByteArray.length);
StringBuilder sb = new StringBuilder();
for (byte b : keyByteArray) {
sb.append(String.format("%02x", b));
}
System.out.println(sb);
System.out.println(sb.length());
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
mac.update(password.getBytes());
byte[] resultByteArray = mac.doFinal();
System.out.println("加密结果:" + resultByteArray.length + "字节");
StringBuilder resultStr = new StringBuilder();
for (byte b : resultByteArray) {
resultStr.append(String.format("%02x", b));
}
System.out.println("加密长度" + resultStr.length());
System.out.println("加密内容:" + resultStr);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
和MD5相比,使用HmacMD5的步骤是:
1.通过名称HmacMD5获取KeyGenerator实例;
2.通过KeyGenerator创建一个SecretKey实例;
3.通过名称HmacMD5获取Mac实例;
4.用SecretKey初始化Mac实例;
5.对Mac实例反复调用update(byte[])输入数据;
6.调用Mac实例的doFinal()获取最终的哈希值。得到加密后的结果。
版权归原作者 磨剑斩秋招 所有, 如有侵权,请联系我们删除。