Java加密解密之MAC(消息认证码)

转载于:https://blog.csdn.net/mn960mn/article/details/78174234

上一篇帖子,我们讲了消息摘要(数字摘要),它是把一个文本/文件 通过摘要函数(hash函数)计算出一个结果。然后把文本/文件和摘要结果一同发给接受者

接受者接收到文件之后,也进行摘要,把两个摘要结果进行对比。如果一致就说明文本/文件和摘要是一致的


但是,这里有个问题,假设A把文件和摘要发给B,中途被C截获了。C把文件改了,同时把改后的文件进行摘要。然后把改后的文件和重新生成的摘要发给B。

B收到结果之后,进行摘要,对比发现,是一致的。但是此时文件是被篡改过的,B也不知道。接收方并不能察觉到数据被篡改。


所以说,普通的消息摘要不能验证身份和防篡改


为了解决这个问题,我们可以使用MAC(消息认证码(带密钥的hash函数))去解决

MAC,全称 Message Authentication Code,也称为消息认证码(带密钥的Hash函数),通信实体双方使用的一种验证机制,保证消息数据完整性的一种工具

在发送数据之前,发送方首先使用通信双方协商好的散列函数计算其摘要值。在双方共享的会话密钥作用下,由摘要值获得消息验证码。之后,它和数据一起被发送。接收方收到报文后,首先利用会话密钥还原摘要值,同时利用散列函数在本地计算所收到数据的摘要值,并将这两个数据进行比对。若两者相等,则报文通过认证。


说白了就是计算摘要的时候,需要一个秘钥key,没有秘钥key就无法计算

注意:相同的消息,不同的key,摘要结果不同。


下面使用Java(1.8.0_144)演示计算apache-tomcat-8.5.23.zip文件的消息摘要

[java]  view plain  copy
  1. package com.security.dgst;  
  2.   
  3. import java.nio.file.Files;  
  4. import java.nio.file.Paths;  
  5. import java.security.Key;  
  6.   
  7. import javax.crypto.Mac;  
  8. import javax.crypto.spec.SecretKeySpec;  
  9.   
  10. import org.apache.commons.codec.binary.Hex;  
  11.   
  12. public class MacTest {  
  13.   
  14.     //秘钥(必须要是通信双方共享的)  
  15.     static final String STR_KEY = "266f5fe18e714688a083df4ca9f78064";  
  16.       
  17.     /** 
  18.      * 其中,Mac.getInstance支持的算法有:HmacMD5、HmacSHA1、HmacSHA256等等 
  19.      * 全部支持的算法见官方文档: 
  20.      * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac 
  21.      */  
  22.     public static byte[] mac(String algorithm, Key key, byte[] data) throws Exception {  
  23.         Mac mac = Mac.getInstance(algorithm);  
  24.         //这里是关键,需要一个key(这里就是和普通的消息摘要的区别点)  
  25.         mac.init(key);  
  26.           
  27.         byte[] result = mac.doFinal(data);  
  28.         return result;  
  29.     }  
  30.       
  31.     public static void main(String[] args) throws Exception {  
  32.         byte[] data = Files.readAllBytes(Paths.get("c:/tmp/apache-tomcat-8.5.23.zip"));  
  33.           
  34.         Key key = new SecretKeySpec(STR_KEY.getBytes(), "");  
  35.           
  36.         //使用MD5算法计算摘要  
  37.         byte[] md5Digest = mac("HmacMD5", key, data);  
  38.           
  39.         //使用SHA256算法计算摘要  
  40.         byte[] shaDigest = mac("HmacSHA256", key, data);  
  41.           
  42.         //把摘要后的结果转换成十六进制的字符串(也可以使用Base64进行编码)  
  43.         System.out.println(Hex.encodeHexString(md5Digest));  
  44.         System.out.println(Hex.encodeHexString(shaDigest));  
  45.     }  
  46. }  
输出结果为:

[plain]  view plain  copy
  1. ce078fe3134fa8b50c595e4e984f88e0  
  2. d90eec24b04b81cd235ff8d4e5a9aeb00183e253e44b6ed763328ff97f856200  

然后,我们可以使用OpenSSL,加上上面使用的秘钥key,计算摘要


对比结果,发现是一致的。


上面的,Mac.getInstance(algorithm)  参数algorithm可以支持的值除了参考官方文档,还可以通过如下代码得出

[java]  view plain  copy
  1. Security.getAlgorithms("Mac").forEach(System.out::println);  
在Java8中,输出结果如下:

[plain]  view plain  copy
  1. PBEWITHHMACSHA512  
  2. PBEWITHHMACSHA224  
  3. PBEWITHHMACSHA256  
  4. HMACSHA384  
  5. PBEWITHHMACSHA384  
  6. HMACSHA256  
  7. HMACPBESHA1  
  8. HMACSHA224  
  9. HMACMD5  
  10. PBEWITHHMACSHA1  
  11. SSLMACSHA1  
  12. HMACSHA512  
  13. SSLMACMD5  
  14. HMACSHA1  

猜你喜欢

转载自blog.csdn.net/x_san3/article/details/80613605
今日推荐