当前位置:   article > 正文

【JavaSE】Java哈希算法。Hmac算法的加密和校验的实现方法_java hmac

java hmac

目录

概述

常用哈希算法

hash算法(消息摘要算法)工具类

加盐的MD5算法

RipeMD160算法

Hmac算法

HMac 加密

HMac密码的校验

按照“字节数组”恢复HMac密钥

按照“字节数组”恢复HMac密钥


概述

哈希算法(Hash)又称摘要算法(Digest),它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。
哈希算法最重要的特点就是:
●相同的输入一定得到相同的输出;
●不同的输入大概率得到不同的输出。
所以,哈希算法的目的:为了验证原始数据是否被篡改。

常用哈希算法

常用哈希算法
算法输出长度(位)输出长度(字节)

MD5

128 bits

16 bytes

SHA-1

160 bits

20 bytes

RipeMD-160

160 bits

20 bytes

SHA-256

256 bits

32 bytes

SHA-512

512 bits

64 bytes

hash算法(消息摘要算法)工具类

此工具类可以有效帮助实现其他hash算法相同的功能

  1. public class HashTools {
  2. private static MessageDigest digest;
  3. private HashTools(){}
  4. //将字节数组转换为16进制字符串
  5. public static String bytesToHex(byte[] bytes){
  6. StringBuilder ret =new StringBuilder();
  7. for (byte b :bytes) {
  8. //将字节数组转换为2位16进制字符串
  9. ret.append(String.format("%02x",b));
  10. }
  11. return ret.toString();
  12. }
  13. //按照MD5进行消息摘要计算(哈希计算)
  14. public static String digestByMD5(String source) throws NoSuchAlgorithmException {
  15. digest = MessageDigest.getInstance("MD5");
  16. return handler(source);
  17. }
  18. //按照SHA-1进行消息摘要计算(哈希计算)
  19. public static String digestBySHA1(String source) throws NoSuchAlgorithmException {
  20. digest = MessageDigest.getInstance("SHA-1");
  21. return handler(source);
  22. }
  23. //按照SHA-256进行消息摘要计算(哈希计算)
  24. public static String digestBySHA256(String source) throws NoSuchAlgorithmException {
  25. digest = MessageDigest.getInstance("SHA-256");
  26. return handler(source);
  27. }
  28. //按照SHA-512进行消息摘要计算(哈希计算)
  29. public static String digestBySHA512(String source) throws NoSuchAlgorithmException {
  30. digest = MessageDigest.getInstance("SHA-512");
  31. return handler(source);
  32. }
  33. //通过消息摘要对象 处理加密内容
  34. private static String handler(String source){
  35. digest.update(source.getBytes());
  36. return bytesToHex(digest.digest());
  37. }

如果只是想要通过MD5,SHA-1,SHA-256,SHA-512进行加密

直接调用此工具类中静态方法即可

  1. //MD5算法加密后生成的字符串
  2. System.out.println("MD5="+HashTools.digestByMD5("wbjxxmy"));
  3. //SHA-1算法加密后生成的字符串
  4. System.out.println("SHA-1="+HashTools.digestBySHA1("wbjxxmy"));
  5. //SHA-256算法加密后生成的字符串
  6. System.out.println("SHA-256="+HashTools.digestBySHA256("wbjxxmy"));
  7. //SHA-512算法加密后生成的字符串
  8. System.out.println("SHA-512="+HashTools.digestBySHA512("wbjxxmy"));

输出结果

但此加密依然存在风险,需注意彩虹表攻击

为了采取特殊措施来抵御彩虹表攻击:我们可以对每个口令额外添加随机数,这个方法称之为加盐(salt)

以MD5算法为例:

加盐的MD5算法

  1. //原始密码
  2. String passWord ="wbjxxmy";
  3. //产生随机的盐值(以随机生成的UUID前四位为例)
  4. String sale = UUID.randomUUID().toString().substring(0,4);
  5. //创建基于MD5算法的消息摘要对象
  6. MessageDigest digest = MessageDigest.getInstance("MD5");
  7. digest.update(passWord.getBytes());//原始密码
  8. digest.update(sale.getBytes());//加盐
  9. //生成的加密结果MD5输出结果位20个字节(40个字符)
  10. System.out.println(Arrays.toString(digest.digest()));//20个字节
  11. System.out.println(HashTools.bytesToHex(digest.digest()));//40长度的字符串

RipeMD160算法

Java标准库并没有提供RipeMD160算法

我们需要找一个现成的第三方库,直接使用。

BouncyCastle就是一个提供了很多哈希算法和加密算法的第三方开源库。它提供了Java标准库没有的一些算法,例如,RipeMD160哈希算法。

首先,我们必须把BouncyCastle提供的bcprov-jdk15on-1.70.jar添加至classpath。这个jar包可以从官方网站下载

其次,Java标准库的java.security包提供了一种标准机制,允许第三方提供商无缝接入。我们要使用BouncyCastle提供的RipeMD160算法,需要先把BouncyCastle注册一下:

  1. // 注册BouncyCastle提供的通知类对象BouncyCastleProvider
  2. Security.addProvider(new BouncyCastleProvider());
  3. // 获取RipeMD160算法的"消息摘要对象"(加密对象)
  4. MessageDigest md = MessageDigest.getInstance("RipeMD160");
  5. // 更新原始数据
  6. md.update("wbjxxmy".getBytes());
  7. // 获取消息摘要(加密)
  8. byte[] result = md.digest();
  9. // 消息摘要的字节长度和内容
  10. System.out.println(result.length); // 160位=20字节
  11. System.out.println(Arrays.toString(result));
  12. // 16进制内容字符串
  13. String hex = new BigInteger(1,result).toString(16);
  14. System.out.println(hex.length()); // 20字节=40个字符
  15. System.out.println(hex);

HMac算法

Hmac算法就是一种基于密钥的消息认证码算法,它的全称是Hash-based Message Authentication Code,是一种更安全的消息摘要算法。
Hmac算法总是和某种哈希算法配合起来用的。例如,我们使用MD5算法,对应的就是Hmac MD5算法,它相当于“加盐”的MD5:HmacMD5 ≈ md5(secure_random_key, input)
因此,HmacMD5可以看作带有一个安全的key的MD5。使用HmacMD5而不是用MD5加salt,有如下好处:
●HmacMD5使用的key长度是64字节,更安全;
●Hmac是标准算法,同样适用于SHA-1等其他哈希算法;
●Hmac输出和原有的哈希算法长度一致。

可见,Hmac本质上就是把key混入摘要的算法。验证此哈希时,除了原始的输入数据,还要提供key。为了保证安全,我们不会自己指定key,而是通过Java标准库的KeyGenerator生成一个安全的随机的key。

HMac 加密

  1. // 获取HmacMD5秘钥生成器
  2. KeyGenerator keyGenerator =KeyGenerator.getInstance("HmacMD5");
  3. // 产生秘钥
  4. SecretKey key = keyGenerator.generateKey();
  5. // 打印随机生成的秘钥:
  6. System.out.println("字节密钥:"+Arrays.toString(key.getEncoded()));//字节输出
  7. System.out.println("字符密钥:"+HashTools.bytesToHex(key.getEncoded()));//字符输出
  8. // 使用HmacMD5加密
  9. Mac mac =Mac.getInstance("HmacMD5");
  10. // 初始化秘钥
  11. mac.init(key);
  12. //对Mac实例反复调用update(byte[])输入数据
  13. mac.update("wbjxxmy".getBytes());
  14. //调用Mac实例的doFinal()获取最终的哈希值。
  15. byte[] bytes = mac.doFinal();
  16. System.out.println("加密后字节:"+Arrays.toString(bytes));
  17. System.out.println("加密后字符:"+HashTools.bytesToHex(bytes));

不过每次生成的密钥都是不同的

切记将其保存

HMac密码的校验

如果我们想要验证该密码,需通过密钥的字节数组或字符串和原始密码通过加密对比

按照“字节数组”恢复HMac密钥
  1. // 原始密码
  2. String password = "nhmyzgq";
  3. // 通过"秘钥的字节数组",恢复秘钥
  4. byte[] bytes ={97, -43, 1, -26, 19, 117, 107, 67, -43, -77, -70, 55, -49, 11, 115,-112, -22, 121, -28, -13, 42, -34, 21, -71, -80, 127, 33, -37, 11, 98, 45, -96, -104, -77, 46, -11, 14, 119, -115, -17, 83, -121, -98, 111, 17, -73, -18, -31, -12, 65, 5, 20, 117, 49, -79, -83, 94, 115, 67, -13, 113, 35, 102, -120};
  5. //恢复密钥
  6. SecretKey key =new SecretKeySpec(bytes,"HmacMD5");
  7. // 加密
  8. Mac mac =Mac.getInstance("HmacMD5");
  9. mac.init(key);
  10. mac.update(password.getBytes());
  11. System.out.println("加密结果:" +HashTools.bytesToHex(mac.doFinal()));
按照“字节数组”恢复HMac密钥
  1. // 原始密码
  2. String password = "nhmyzgq";
  3. //使用字符串密钥 校验
  4. String keyWord ="61d501e613756b43d5b3ba37cf0b7390ea79e4f32ade15b9b07f21db0b622da098b32ef50e778def53879e6f11b7eee1f44105147531b1ad5e7343f371236688";
  5. byte[] bytes =new byte[64];
  6. //将字符密钥以每两个字符转换位一个字节
  7. for (int i = 0,k=0; i <keyWord.length() ; i+=2,k++) {
  8. String s = keyWord.substring(i, i + 2);
  9. bytes[k] = (byte)Integer.parseInt(s,16);
  10. }
  11. //恢复密钥
  12. SecretKey key =new SecretKeySpec(bytes,"HmacMD5");
  13. // 加密
  14. Mac mac =Mac.getInstance("HmacMD5");
  15. mac.init(key);
  16. mac.update(password.getBytes());
  17. System.out.println("加密结果:" +HashTools.bytesToHex(mac.doFinal()));

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/447842
推荐阅读
相关标签
  

闽ICP备14008679号