关于哈希算法的应用

文章介绍了哈希算法的基本概念和作用,如验证数据完整性。它详细阐述了哈希碰撞及其在彩虹表攻击中的影响,以及如何通过加盐方式提高安全性。此外,文章还列举了MD5、SHA-1、SHA-256、SHA-512等常见哈希算法的使用示例,并提到了RipeMd-160和Hmac作为更安全的消息认证码算法。
摘要由CSDN通过智能技术生成

一、概述

        哈希算法(Hash)又称摘要算法(Digest)。它可以对任意一组输入数据进行计算,得到一个固定长度的输出摘要。哈希算法的目的:验证原始数据是否被修改。

二、哈希碰撞

        哈希碰撞就是输入两个不同的数据,得到两个相同的结果。哈希碰撞不能避免,所以我们可以利用一些算法来减少哈希碰撞发生的概率。

三、彩虹表攻击

        直接将用户的原始口令存放在数据库中,数据库一旦泄露,黑客即可获取用户信息。当黑客获取到MD5口令后,通过暴力穷举的方法就可以反推用户密码。但这样费时费力,所以就有了一个预先计算好的常用口令和它们的MD5对照表,这个表就叫彩虹表。

四、常用的哈希算法

        前提:Hash算法工具类

示例代码

//Hash算法(消息摘要算法)工具类
public class HashTools {
	
    //消息摘要对象
	private static MessageDigest digest;
	
    //构造方法私有
	private HashTools() {}
	
    //按照MD5进行消息摘要计算(哈希计算)
	public static String digestByMD5(String source) throws NoSuchAlgorithmException {
		digest = MessageDigest.getInstance("MD5");
		return handler(source);
	}
	
    //按照SHA-1进行消息摘要计算(哈希计算)
	public static String digestBySHA1(String source) throws NoSuchAlgorithmException {
		digest = MessageDigest.getInstance("SHA-1");
		return handler(source);
	}
	
    //按照SHA-256进行消息摘要计算(哈希计算)
	public static String digestBySHA256(String source) throws NoSuchAlgorithmException {
		digest = MessageDigest.getInstance("SHA-256");
		return handler(source);
	}
	
    //按照SHA-512进行消息摘要计算(哈希计算)
	public static String digestBySHA512(String source) throws NoSuchAlgorithmException {
		digest = MessageDigest.getInstance("SHA-512");
		return handler(source);
	}
	
    //通过消息摘要对象,处理加密内容
	private static String handler(String source) {
		digest.update(source.getBytes());
		byte[] bytes = digest.digest();
		String hash = bytestoHex(bytes);
		return hash;
	}

	//将字节数组转换为十六进制字符串
	public static String bytestoHex(byte[] bytes) {
		StringBuilder ret = new StringBuilder();
		for(byte b : bytes) {
			//将字节值转换为两位十六进制字符串
			ret.append(String.format("%02x", b));
		}
		return ret.toString();
		
	}
	
}

        1、MD5

        MD5算法的固定输出长度为16个字节

利用MD5算法实现文字加密,示例代码

//创建基于MD5算法的消息摘要对象
MessageDigest md5 = MessageDigest.getInstance("MD5");
	
//更新原始数据	
md5.update("高堂明镜悲白发,朝如青丝暮成雪".getBytes());
	
//获取加密后的结果	
byte[] mdbytes = md5.digest();
System.out.println("加密后的结果(字节数组):"+Arrays.toString(mdbytes));
System.out.println("加密后的结果(字符数组):"+HashTools.bytestoHex(mdbytes));
System.out.println("加密后的长度:"+mdbytes.length);

利用MD5算法实现图片加密,示例代码

//按照MD5算法对图片进行加密
//图片的原始字节内容
byte[] imageBuff = Files.readAllBytes(Paths.get("E:\\test\\love.jpg"));
	
//创建基于MD5算法的消息摘要对象	
MessageDigest md5 = MessageDigest.getInstance("MD5");

//原始字节内容(图片)		
md5.update(imageBuff);

//获取加密摘要		
byte[] mdbytes = md5.digest();
System.out.println("加密后的结果(字节数组):"+Arrays.toString(mdbytes));
System.out.println("加密后的结果(字符数组 ):"+HashTools.bytestoHex(mdbytes));
System.out.println("加密后的长度:"+mdbytes.length);

        2、SHA-1

通过随机加盐解决彩虹表攻击问题,示例代码

//原始密码
String password = "gtbjbbf";

//产生随机的盐值
//盐值的位数和内容可以自己设定,比如我所设定的五位随机数
String salt = UUID.randomUUID().toString().substring(0,5);
	
//创建基于SHA-1算法的消息摘要对象	
MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
sha1.update(password.getBytes());//原始密码
sha1.update(salt.getBytes());//盐值
		
//计算加密结果,SHA-1的输出结果为20个字节(40个字符)
String saltRet = HashTools.bytestoHex(sha1.digest());
System.out.println(saltRet);

        3、SHA-256

        类似于MD5和SHA-1算法,只需要将传入名称改为SHA-256即可。

        4、SHA-512

调用工具类方法进行计算,示例代码

try {
		String md5 = HashTools.digestByMD5("gtmjbbf");
		String sha1 = HashTools.digestBySHA1("gtmjbbf");
		String sha256 = HashTools.digestBySHA256("gtmjbbf");
		String sha512 = HashTools.digestBySHA512("gtmjbbf");
			
		System.out.println("md5:"+md5);
		System.out.println("sha1:"+sha1);
		System.out.println("sha256:"+sha256);
		System.out.println("sha512:"+sha512);
			
			
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}

        5、RipeMd-160

        使用第三方开源库提供的RipeMD-160消息摘要算法实现步骤:

        1、注册BouncyCastleProvider通知类,将提供的消息摘要算法注册至Security。

        2、获取RipeMD-160算法的“消息摘要对象”(加密对象)

        3、更新原始数据

        4、获取消息摘要(加密)

示例代码

//使用第三方开源库提供的RipeMD-160消息摘要算法实现
//注册BouncyCastleProvider通知类
//将提供的消息摘要算法注册至Security
Security.addProvider(new BouncyCastleProvider());

//获取RipeMD-160算法的“消息摘要对象”(加密对象)	
MessageDigest ripeMd160 = MessageDigest.getInstance("RipeMD160");
		
//更新原始数据
ripeMd160.update("gtmjbbf".getBytes());
		
//获取消息摘要(加密)
byte[] result = ripeMd160.digest();
		
//消息摘要的字节长度和内容
System.out.println("加密结果(字节长度):"+result.length);
System.out.println("加密结果(字节内容):"+Arrays.toString(result));
		
//16进制内容字符串
String hex = new BigInteger(1,result).toString(16);
System.out.println("加密结果(字符串长度):"+hex.length());
System.out.println("加密结果(字符串内容):"+hex);

        6、Hmac

        Hmac算法是一种基于密钥的消息认证码算法,全称Hash-base Message Authentication Code,是一种更安全的算法。它总是和某种哈希算法配合起来用的。        

        例如HmacMD5:

Hmac算法示例代码

//Hmac算法
//获取HmacMD5密钥生成器
KeyGenerator KeyGen = KeyGenerator.getInstance("HmacMD5");

String password = "gtmjbbf";

//生成密钥		
SecretKey key = KeyGen.generateKey();
System.out.println("密钥(字节数组):"+Arrays.toString(key.getEncoded()));
System.out.println("密钥长度:"+key.getEncoded().length);
System.out.println("密钥:"+HashTools.bytestoHex(key.getEncoded()));
		
//使用密钥,进行加密	
//获取Hmac加密算法对象	
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);//初始化密钥	
mac.update(password.getBytes());//更新元原始加密内容
byte[] bytes = mac.doFinal();//加密处理,并获取加密结果
String ret = HashTools.bytestoHex(bytes);//加密结果处理成16进制字符串
System.out.println("加密结果:"+ret);
System.out.println("加密结果长度(字符):"+ret.length());
System.out.println("加密结果长度(字节):"+bytes.length);

按照“字节数组”,恢复Hmac密钥,示例代码

//原始密码
String password = "gtmjbbf";

//密钥(字节数组)		
byte[] keyBytes = {-120, -82, 22, 60, 15, -23, -94, -75, 109, -39, 17, -50, 4, 83, -88, -3, -126, 86, -28, 47, -54, -119, -76, -52, 14, 87, -8, 101, 82, -54, 79, 122, -116, 19, 73, 75, 22, 25, 80, -101, 111, -45, -70, 8, -31, 125, -123, 23, 114, -88, 111, -38, 114, -77, 98, 126, 99, 21, 84, -11, 119, 81, -62, 83};

//恢复密钥(字节数组)
SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
		
//创建加密算法对象
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);//初始化密钥
mac.update(password.getBytes());
byte[] bytes = mac.doFinal();//加密处理,并获取加密结果
String ret = HashTools.bytestoHex(bytes);
System.out.println(ret);//7a9542533a479363a848f2ba26ab1861

按照“字符串”,恢复Hmac密钥,示例代码

String password = "gtmjbbf";

//密钥(字符串)	
String keyStr = "9ccc5b3bb0cca1239090646812eb724459fbeeb7bd21bb1d3ecd7e4d74a63ce244bf1abd446cc4fd2592bbe66e16a09e65febbe9c8dd3a682fd52edfb7461535";

//用于保存密钥:密钥长度为64字节
byte[] keyBytes = new byte[64];
		
for(int i = 0,k = 0;i < keyStr.length();i += 2,k++) {
			
	String s = keyStr.substring(i,i+2);
	keyBytes[k] = (byte) Integer.parseInt(s,16);//转换为16进制byte值
}
		
SecretKey key = new SecretKeySpec(keyBytes, "HmacMD5");
Mac mac = Mac.getInstance("HmacMD5");
mac.init(key);
mac.update(password.getBytes());
byte[] bytes = mac.doFinal();//加密处理,并获取加密结果
String ret = HashTools.bytestoHex(bytes);
System.out.println("加密结果:"+ret);//d46d6b66f146bd468d19800671dc7594
System.out.println("加密结果长度(字符):"+ret.length());
System.out.println("加密结果长度(字节):"+bytes.length);

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值