什么是哈希(Hsah)算法,哈希算法的作用以及Java中常见的哈希算法的使用案例。

一、了解哈希算法

1、简介

        Hash算法(又称摘要算法),一般翻译做散列或音译为哈希,哈希算法具有不可逆性、压缩性、高效性等重要特点,可以将任意长度的数据转换成一个固定长度的哈希值。该输出就是散列值。这种转换是一种压缩映射,一般输出长度会远远小于输入长度,不同的输入大概率会产生不同的输出(由于哈希冲突,可能会造成不同输入相同输出的情况发生),故不能通过散列值来确定唯一值,简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

2、哈希碰撞

        什么是哈希碰撞?当我们对一个元素进行哈希运算时得到了一个储存地址,但该地址已经被其他元素占用,当我们对key1和key2进行Hash运算时,key1 ≠ key2时但计算的f(key1)=f(key2),即发生了哈希碰撞,也叫哈希冲突。哈希碰撞不可被避免,因为输出的散列值长度是固定的,但输入值的数量是无穷的,无限的输入散列到有限的输出中必将产生产生重复值,但可以通过对算法的优化减少哈希碰撞。

3、哈希算法的作用

        哈希算法可以用于用户密码的安全存储和验证。具体实现方法为将用户密码经过哈希算法处理得到哈希值,然后将这个哈希值存储在数据库中。用户登录时,输入密码后,系统将输入的密码经过哈希运算得到一个新的哈希值,将这个哈希值和数据库中存储的哈希值进行比对,如果相同,则说明用户密码正确,可以登录系统。哈希算法在身份认证中的应用已经被广泛应用于各种网站和应用程序的用户密码管理中。哈希算法也可以对文件的下载进行校验,使用哈希算法对文件进行哈希值计算,如果文件内用被篡改,则可通过哈希值对比进行校验文件的完整性。

4、常见的Hash算法

  1. MD5                  输出长度16bytes
  2. SHA-1               输出长度20bytes
  3. RiprMD-160      输出长度20bytes
  4. SHA-256           输出长度32bytes
  5. SHA-512           输出长度64bytes

二、如何在Java中使用Hash算法

1.基本使用

在Java的核心类库中已经集成了MD5、SHA-1等Hash算法,一下我们以MD5算法为例:

(1).获取消息摘要对象

        使用静态方法MessageDigest.getInstance()获取消息摘要对象,传入需要使用的算法模型。

(2).更新原始数据

        使用MessageDigest对象的update()方法传入需要进行哈希运算的对象,传入的对象需要转化为一个字节数组,将对象一次传入或分为多个字节数组依次传入,如若顺序不变则计算的结果不变。

(3).获取加密后的结果

在完成对所需进行Hash运算对象的更新后,调用MessageDigest对象的digest()方法获取运算结果,运算的结果也为一个字节数组,字节数组的长度根据所选算法的不同而有所差异,MD5计算生成是字节数组长度为16,在此便获取到了《静夜思》进行MD5哈希运算后的结果:

hash加密后:[-76, -115, 46, -62, 81, 46, 81, -21, 2, 110, 13, -111, 36, -40, -70, 112]

由于字节数组不便于传输,我们通常将他处理为一串16进制的字符串,通过处理后我们的结果就变为了:b48d2ec2512e51eb026e0d9124d8ba70

    //需要加密的对象
    String message="床前明月光,疑是地上霜,举头望明月,低头思故乡。";
    //创建基于MD5算法的消息摘要对象
    MessageDigest digest=MessageDigest.getInstance("MD5");
    //更新原始数据
	digest.update(message.getBytes());
    //获取加密后的结果
	byte[] buff=digest.digest();
    //查看Hash加密后的结果
    System.out.println("hash加密后:"+Arrays.toString(buff));
    StringBuilder sb=new StringBuilder(32);
		for(byte b:buff) {
			sb.append(String.format("%02x", b));
		}
    //将字节数组转化为16进制后的结果
	System.out.println(sb.toString());

2.加盐存储

        我们通常使用Hash算法来对用的的密码等敏感信息进行加密存储,但由于Hash算法固定输入固定输出的特性,可以使用彩虹表攻击,用暴力字典比对等方法倒推出用户的敏感信息,为例避免这种情况发生,我们可以使用加盐的方式即向需要加密的信息中添加一小段而外的“干扰信息”,使得所计算的哈希值发生变化。例如我们的密码是123456,经过MD5哈希加密后转化为十六进制后的结果为:e10adc3949ba59abbe56e057f20f883e,则可建立字典对应,当发现对应的哈希值后便可以倒推出我们的密码,但如果我们添加一段随机字符在对密码进行哈希运算,便很难对其进行建立字典,而我们只需保存生成的随机字符,便可对密码进行哈希运算进行比对。

    String message="123456";
    //生成随机字符串
    String salt=UUID.randomUUID().toString().substring(0, 4);
    //创建基于MD5算法的消息摘要对象
    MessageDigest digest=MessageDigest.getInstance("MD5");
    //更新原始数据
	digest.update(message.getBytes());
    //加盐
    digest.update(salt.getBytes());
    //获取加密后的结果
	byte[] buff=digest.digest();
		

三.使用第三方提供的Hash算法模型

我们可以使用第三方提供的类库来使用其他的哈希算法模型,例如bcprov-jdk15on-1.70.jar,他的使用步骤和Java核心类库提供的哈希算法使用步骤相同,只需要提前注册BouncyCsatleProvider通知类将提供的消息摘要算法注册至Security即可。

    //注册BouncyCsatleProvider通知类
	//将提供的消息摘要算法注册至Security
	Security.addProvider(new BouncyCastleProvider());
	MessageDigest digest=MessageDigest.getInstance("RipeMd160");
	digest.update("我本将心向明月".getBytes());
	byte[] bytes=digest.digest();

四.Hmac算法

        Hmac算法是一种基于秘钥的消息认证码算法,他是一种安全的消息摘要算法。Hmac算法总是和某种哈希算法配合起来使用,例如MD5算法,从某种程度来说它就相当于“加盐”的MD5算法,它是一个带有一个安全的key的Md5算法。可见,Hmac本质上就是把key混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供key。为了保证安全,我们不会自己指定key,而是通过Java标准库的KeyGenerator生成一个安全的随机的key。

    //获取HmacMD5秘钥生成器
    KeyGenerator generator=KeyGenerator.getInstance("HmacMD5");
    //获取生成秘钥
    SecretKey key=generator.generateKey();
    //查看秘钥内容
    System.out.println(Arrays.toString(key.getEncoded()));
    //将秘钥转化为十六进制字符串
    System.out.println(DigestUtils.bytesToHex(key.getEncoded()));
    //获取HmacMD5算法加密对象
    Mac mac=Mac.getInstance("HmacMd5");
    //初始化秘钥
    mac.init(key);
    //更新原始加密内容
    mac.update("wbjxxmy".getBytes());
    //执行加密算法获取加密内容
    byte[] bytes=mac.doFinal();

        在需要对内容进行比对时,我们只需要拿出保存好的秘钥字节数组或者转化为十六进制的字符串,对需要比对的内容进行HmacMD5加密,对加密结果进行比对即可。

   //如果为十六进制字符串,则需要将其转换为字节数组
    byte[] bytes=DigestUtils.hexToBytes("b93524196fe621ee3f4900c6
          5b03119c4b15da2f516153b1c529eaa1f152b858
          fda0de38917e776eb8864493a0ad810790cdf82d
          8b6c2f3f0fc1fc8a9b72e569");
    //通过字节数组生成HmacMD5算法的key
	SecretKey key=new SecretKeySpec(bytes, "HmacMD5");
     Mac mac=Mac.getInstance("HmacMd5");
    //初始化秘钥
    mac.init(key);
    //更新原始加密内容
    mac.update("wbjxxmy".getBytes());
    //执行加密算法获取加密内容,之后与存储的哈希值进行对比即可
    byte[] bytes=mac.doFinal();

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

‏猿究院Sublate

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值