Java加密解密之MAC(訊息認證碼)
阿新 • • 發佈:2019-01-08
上一篇帖子,我們講了訊息摘要(數字摘要),它是把一個文字/檔案 通過摘要函式(hash函式)計算出一個結果。然後把文字/檔案和摘要結果一同發給接受者
接受者接收到檔案之後,也進行摘要,把兩個摘要結果進行對比。如果一致就說明文字/檔案和摘要是一致的
但是,這裡有個問題,假設A把檔案和摘要發給B,中途被C截獲了。C把檔案改了,同時把改後的檔案進行摘要。然後把改後的檔案和重新生成的摘要發給B。
然後,我們可以使用OpenSSL,加上上面使用的祕鑰key,計算摘要
接受者接收到檔案之後,也進行摘要,把兩個摘要結果進行對比。如果一致就說明文字/檔案和摘要是一致的
但是,這裡有個問題,假設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檔案的訊息摘要
輸出結果為:package com.security.dgst; import java.nio.file.Files; import java.nio.file.Paths; import java.security.Key; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; public class MacTest { //祕鑰(必須要是通訊雙方共享的) static final String STR_KEY = "266f5fe18e714688a083df4ca9f78064"; /** * 其中,Mac.getInstance支援的演算法有:HmacMD5、HmacSHA1、HmacSHA256等等 * 全部支援的演算法見官方文件: * https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Mac */ public static byte[] mac(String algorithm, Key key, byte[] data) throws Exception { Mac mac = Mac.getInstance(algorithm); //這裡是關鍵,需要一個key(這裡就是和普通的訊息摘要的區別點) mac.init(key); byte[] result = mac.doFinal(data); return result; } public static void main(String[] args) throws Exception { byte[] data = Files.readAllBytes(Paths.get("c:/tmp/apache-tomcat-8.5.23.zip")); Key key = new SecretKeySpec(STR_KEY.getBytes(), ""); //使用MD5演算法計算摘要 byte[] md5Digest = mac("HmacMD5", key, data); //使用SHA256演算法計算摘要 byte[] shaDigest = mac("HmacSHA256", key, data); //把摘要後的結果轉換成十六進位制的字串(也可以使用Base64進行編碼) System.out.println(Hex.encodeHexString(md5Digest)); System.out.println(Hex.encodeHexString(shaDigest)); } }
ce078fe3134fa8b50c595e4e984f88e0
d90eec24b04b81cd235ff8d4e5a9aeb00183e253e44b6ed763328ff97f856200
然後,我們可以使用OpenSSL,加上上面使用的祕鑰key,計算摘要
對比結果,發現是一致的。
上面的,Mac.getInstance(algorithm) 引數algorithm可以支援的值除了參考官方文件,還可以通過如下程式碼得出
Security.getAlgorithms("Mac").forEach(System.out::println);
在Java8中,輸出結果如下:
PBEWITHHMACSHA512 PBEWITHHMACSHA224 PBEWITHHMACSHA256 HMACSHA384 PBEWITHHMACSHA384 HMACSHA256 HMACPBESHA1 HMACSHA224 HMACMD5 PBEWITHHMACSHA1 SSLMACSHA1 HMACSHA512 SSLMACMD5 HMACSHA1