Java哈希算法总结

一、编码算法

编码是直接给每个字符指定一个若干字节表示的整数。

常见的编解码算法有:URL编码、Base64编码。

1、URL编码是浏览器发送数据给服务器时使用的编码。

特点:把数据编码成前缀为%表示的字符串。

URL编码对A(a)-Z(z),0-9, - , _ , . , * 这些字符不进行编码,除此以外的字符则需要进行编码。

URLEncoder类:对URL进行斑马操作的。

有编码必然有解码,URLDecoder类:对URL进行解码操作的。

 2.Base64编码:将字节数组编码成字符串或将字符串解码为字节数组

特点:把字符编码成%xx表示的形式。

 二、哈希算法

1、哈希算法又称摘要算法,作用是对任意一组输入数据进行计算,得到一个固定长度的输出摘要。

目的:验证原始数据是否被篡改。

2、哈希碰撞是指:两个不同的输入得到了相同的输出。

哈希碰撞不能避免,因为输出的字节长度是固定的,而且最多有4294967296中输出,但是有无限种输入。

3、常见的哈希算法:MD5算法,SHA-1(20字节),SHA-256(32字节),SHA-512(64字节),RipeMD-160算法(Java标准类库中没有提供RipeMD-160算法)。

MD5算法(长度:16字节)

 需要编写一个hash算法的工具类,定义bytesToHex()方法,将字节数组转换为十六进制字符串。

 SHA-1算法:与MD5使用方法一样,只用在实例化MessageDigest对象时将传入的参数改为"SHA-1"即可。

RipeMD160算法

public class Demo03 {
	//使用第三方开源库提供的RipeMD160消息摘要算法实现
	public static void main(String[] args) throws NoSuchAlgorithmException {
		//注册BouncyCastleBouncyCastleProvider通知类
		//将提供的消息摘要算法注册至Security
		Security.addProvider(new BouncyCastleProvider());
		
		//获取RipeMD160算法的“消息摘要对象”(加密对象)
		MessageDigest ripeMd160 = MessageDigest.getInstance("RipeMD160");
		//更新原始数据
		ripeMd160.update("wbjxxmy".getBytes());
		//获取消息摘要(加密)
		byte[] result = ripeMd160.digest();
		//消息摘要的字节长度和内容
		System.out.println("加密结果(字节长度):"+result.length);//160位=20字节
		System.out.println("加密结果(字节内容):"+Arrays.toString(result));
		
		//16进制内容字符串
		String hex = new BigInteger(1,result).toString(16);
		System.out.println("加密结果(字符串长度):"+hex.length());
		System.out.println("加密结果(字符串内容):"+hex);
	}
}

4.存储用户密码

如果直接将用户的密码不做任何处理直接放入数据库中,会存在很大的安全风险。所以改进方法是存储用户密码的哈希。

什么是彩虹表攻击?例如:使用MD5。就是将常用口令和它们MD5制作成一张表(这个表足够庞大),这个表就是彩虹表。为了防止彩虹表攻击,对每个口令前面追加一些额外的数字,这就是盐值。

 5.解决MD5算法与SHA-1算法代码冗余

//hash算法工具类
public class HashTools {
	//定义全局变量,消息摘要对象
	private static MessageDigest digest;
	
	//构造方法私有
	private HashTools() {}
	
	//按照MD5进行消息摘要算法(哈希计算)
	public static String digestByMD5(String source) throws NoSuchAlgorithmException {
		//基于MD5算法
		digest = MessageDigest.getInstance("MD5");
		return handler(source);
	}
	//按照SHA-1进行消息摘要算法(哈希计算)
	public static String digestBySHA1(String source) throws NoSuchAlgorithmException {
		//基于SHA-1算法
		digest = MessageDigest.getInstance("SHA-1");
		return handler(source);
	}
	//通过消息摘要对象,处理加密内容
	private static String handler(String source) {
		//更新原始数据
		digest.update(source.getBytes());
		//进行加密处理
		byte[] bytes = digest.digest();
		//将字节数组转换成十六进制
		String hash = bytesToHex(bytes);
		return hash;
	}
	//将字节数组转换为16进制字符串
	public static String bytesToHex(byte[] bytes) {
		StringBuilder ret = new StringBuilder();
		for(Byte b : bytes) {
			//将字节值转换为2位十六进制字符串
			ret.append(String.format("%02x", b));
		}
		return ret.toString();
	}
}

三、Hmac算法

Hmac算法:基于秘钥的消息摘要算法.也是一种防御彩虹表攻击的算法,它比"加盐"这种方式的安全性更高。

1、使用秘钥生成器生成秘钥,进行加密处理

public class Demo01 {
	public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
		String password = "wbjxxmy";
		//1.产生秘钥
		//获取HmacMD5秘钥生成器
		KeyGenerator keyGen = KeyGenerator.getInstance("HmacMD5");
		//生成密钥
		SecretKey key = keyGen.generateKey();
		System.out.println("秘钥:"+Arrays.toString(key.getEncoded()));
		System.out.println("秘钥长度(64字节):"+key.getEncoded().length);
		System.out.println("秘钥:"+HashTools.bytesToHex(key.getEncoded()));
		
		//2.使用秘钥,进行加密
		//获取HMac加密算法
		//创建Mac对象,传入"HmacMD5"算法
		Mac mac = Mac.getInstance("HmacMD5");
		//初始化秘钥
		mac.init(key);
		//更新原始加密内容
		mac.update(password.getBytes());
		//加密处理,并获取加密结果 
		byte[] bytes = mac.doFinal();
		//加密结果处理成16进制字符串
		String result = HashTools.bytesToHex(bytes);
		System.out.println("加密结果16进制字符串:"+result);
		System.out.println("加密结果(字节长度16字节):"+bytes.length);
		System.out.println("加密结果(字符长度32字节):"+result.length());
	}
}

2、给定秘钥字节数组,恢复Hmac秘钥

给定一个秘钥字节数组,先将其恢复成秘钥对象,再进行加密处理。

//秘钥(字节数组)
		byte[] keyBytes = {51, 8, 87, 91, 106, -78, 70, -119, 5, -75, 78, -52, -62, -33, 
				-64, -102, 80, 56, 7, -43, -115, 57, 29, 69, -61, 121, -37, -47, -95, 
				66, -82, -116, -22, 19, -8, -42, 127, 67, 18, -109, -9, 89, 7, 6, 59, 
				-63, 51, 35, 0, 45, -102, -20, -82, -82, 29, -105, 10, 0, -110, -70, 76,
				-102, -57, 50};
		try {
			//恢复秘钥(字节数组)
			SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
			//创建Hmac加密算法对象
			Mac mac = Mac.getInstance("HmacMD5");
			//初始化秘钥
			mac.init(key);
			//更新原始加密内容
			mac.update(password.getBytes());
			//加密结果处理成16进制字符串
			String result = HashTools.bytesToHex(mac.doFinal());
			//输出
			System.out.println(result);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}

3、按照"字符串",恢复Hmac秘钥

先将字符串转换成字节数组再进行后续步骤。

//秘钥(字符串)
		String keyStr = "1dbb7361d48949df91e3ff0c5fab8666c5358a8daf965d6"
				+ "bbd84ff90e17c3a365b2c6613ac257ae961d75402e88d47c6a0854de60cde"
				+ "00.070982b3e437e4dec91af";
		//用于保存秘钥,秘钥长度为64字节
		byte[] keyBytes = new byte[64];
		//遍历字符串,将其保存进字节数组keyBytes中
		for(int i = 0,k = 0;i < keyStr.length();i += 2,k++) {
			//每次截取两位
			String s = keyStr.substring(i,i+2);
			//将截取的两位字符转换成16进制,放入字节数组中
			keyBytes[k] = (byte) Integer.parseInt(s,16);
		}
		try {
			//恢复秘钥(字节数组)
			SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
			//创建Hmac加密算法对象
			Mac mac = Mac.getInstance("HmacMD5");
			//初始化秘钥
			mac.init(key);
			//更新原始加密内容
			mac.update(password.getBytes());
			//加密结果处理成16进制字符串
			String result = HashTools.bytesToHex(mac.doFinal());
			//输出
			System.out.println(result);
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值