昨天我們介紹了《「後端」加密算法之 SHA 算法》,今天我們開始介紹消息摘要算法中的 HMAC(Keyed-Hashing for Message Authentication)消息認證碼算法,MAC(Message Authentication Code,消息認證碼算法)是含有密鑰散列函數算法,相容了 MD 和 SHA 算法的特性,并在此基礎上加上了密鑰,是以MAC算法也經常被稱作 HMAC 算法。
MAC
在開始之前,我們先說下MAC算法。在現代的網絡中,身份認證是一個經常會用到的功能,在身份認證過程中,有很多種方式可以保證使用者資訊的安全,而 MAC(message authentication code) 就是一種常用的方法。
消息認證碼是對消息進行認證并确認其完整性的技術。通過使用發送者和接收者之間共享的密鑰,就可以識别出是否存在僞裝和篡改行為。
MAC 是通過【MAC 算法 + 密鑰 + 要加密的資訊】三個要素一起計算得出的。
同hash算法(消息摘要)相比,消息摘要隻能保證消息的完整性,即該消息摘要B是這個消息A生成的。而MAC算法能夠保證消息的正确性,即判斷确實發的是消息A而不是消息C。
同公私鑰體系相比,因為MAC的密鑰在發送方和接收方是一樣的,是以發送方和接收方都可以來生成MAC,而公私鑰體系因為将公鑰和私鑰分開,是以增加了不可抵賴性。
MAC有很多實作方式,比較通用的是基于hash算法的MAC,比如今天我們要講的HMAC算法。還有一種是基于分組密碼的實作,比如OMAC, CBC-MAC and PMAC等。
HMAC
HMAC 算法首先它是基于資訊摘要算法的。目前主要集合了MD和SHA兩大系列消息摘要算法。其中MD系列的算法有HmacMD2、HmacMD4、HmacMD5三種算法;SHA系列的算法有HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512五種算法。
HMAC 算法除了需要資訊摘要算法外,還需要一個密鑰。HMAC的密鑰可以是任何長度,如果密鑰的長度超過了摘要算法資訊分組的長度,則首先使用摘要算法計算密鑰的摘要作為新的密鑰。一般不建議使用太短的密鑰,因為密鑰的長度與安全強度是相關的。通常選取密鑰長度不小于所選用摘要算法輸出的資訊摘要的長度。
MD 算法的對比
算法 | 摘要長度(bit) | 實作方 |
HmacMD5 | 128 | JDK、Bouncy Castle、Commons Codec |
HmacSHA1 | 160 | JDK、Bouncy Castle、Commons Codec |
HmacSHA224 | 224 | JDK、Bouncy Castle、Commons Codec |
HmacSHA256 | 256 | JDK、Bouncy Castle、Commons Codec |
HmacSHA384 | 384 | JDK、Bouncy Castle、Commons Codec |
HmacSHA512 | 512 | JDK、Bouncy Castle、Commons Codec |
HMAC 算法實作
JDK 的 HMAC 算法實作
// 擷取 HMAC Key
public static byte[] getHmacKey(String algorithm) {
try {
// 1、建立密鑰生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
// 2、産生密鑰
SecretKey secretKey = keyGenerator.generateKey();
// 3、擷取密鑰
byte[] key = secretKey.getEncoded();
// 4、傳回密鑰
return key;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// HMAC 加密
public static String encryptHmac(byte[] data, byte[] key, String algorithm) {
try {
// 1、還原密鑰
SecretKey secretKey = new SecretKeySpec(key, algorithm);
// 2、建立MAC對象
Mac mac = Mac.getInstance(algorithm);
// 3、設定密鑰
mac.init(secretKey);
// 4、資料加密
byte[] bytes = mac.doFinal(data);
// 5、生成資料
String rs = encodeHex(bytes);
// 6、傳回十六進制加密資料
return rs;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Bouncy Castle 的HMAC 算法實作
// 擷取 HMAC Key
public static byte[] getHmacKey(String algorithm) {
try {
// 1、建立密鑰生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
// 2、産生密鑰
SecretKey secretKey = keyGenerator.generateKey();
// 3、擷取密鑰
byte[] key = secretKey.getEncoded();
// 4、傳回密鑰
return key;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// HMAC 加密
public static String encryptHmac(byte[] data, byte[] key, String algorithm) {
HMac hmac = generateHmacByAlgorithm(algorithm);
KeyParameter keyParameter = new KeyParameter(key);
hmac.init(keyParameter);
hmac.update(data, 0, data.length);
byte[] rsData = new byte[hmac.getMacSize()];
hmac.doFinal(rsData, 0);
return Hex.toHexString(rsData);
}
Commons Codec 的HMAC 算法實作
// 擷取 HMAC Key
public static byte[] getHmacKey(String algorithm) {
try {
// 1、建立密鑰生成器
KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);
// 2、産生密鑰
SecretKey secretKey = keyGenerator.generateKey();
// 3、擷取密鑰
byte[] key = secretKey.getEncoded();
// 4、傳回密鑰
return key;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// HMAC 加密
public static String encryptHmac(byte[] data, byte[] key, String algorithm) {
Mac mac = HmacUtils.getInitializedMac(HmacAlgorithms.HMAC_MD5, key);
return Hex.encodeHexString(mac.doFinal(data));
}
HMAC 算法的應用
1、可以驗證對端使用者的合法性
HMAC算法的一個典型應用是用在“挑戰/響應”(Challenge/Response)身份認證中,認證流程如下:
(1) 先由用戶端向伺服器發出一個驗證請求,(假設是浏覽器的GET請求)。
(2) 伺服器接到此請求後生成一個随機數并通過網絡傳輸給用戶端(此為挑戰)。
(3) 用戶端将收到的随機數與自己的密鑰進行HMAC運算并得到一個結果作為認證證據傳回給伺服器(此為響應)。
(4) 與此同時,伺服器也使用該随機數與存儲在伺服器資料庫中的該客戶密鑰進行HMAC運算,如果伺服器的運算結果與用戶端傳回的響應結果相同,則認為用戶端是一個合法使用者 。
在這個過程中,可能遭到安全攻擊的是伺服器發送的随機數和用戶端傳回的HMAC結果,而對于截獲了這兩個值的黑客而言這兩個值是沒有意義的,随機值的引入使HMAC隻在目前會話中有效,大大增強了安全性和實用性。
2、發消息給對方(或從對方接收消息)
比如你和對方共享了一個密鑰K,現在你要發消息給對方,既要保證消息沒有被篡改(完整性),又要能證明資訊确實是你本人發的(源認證),那麼就把原資訊和密鑰K經 HMAC 計算的值一起發過去。對方接到之後,使用自己手中的密鑰K和原消息計算一下HMAC的值,如果和你發送的HMAC一緻,那麼可以認為這個消息既沒有被篡改也沒有冒充。
普通雜湊演算法和 HMAC 算法的差別
普通雜湊演算法就是通過hash對要輸出的資料進行摘要,接收到資料時,再同樣對源資料進行散列,與給定的散列值比較,看收到的資料與計算的hash值是否一緻就可以了。
通常來說,傳輸的資料和散列值是不同的管道給出的,比如網頁上顯示MD5或SHA的散列值,但是下載下傳連結是某個鏡像網站的,這并不影響你下載下傳到的檔案的正确性。
如果要通過同一個管道發送資料和散列值的話(比如消息認證碼),就要考慮資料和散列值是否會同時被篡改的問題,如果第三方修改了資料,然後進行MD5散列,并一塊發給接收方,接收方并不能察覺到資料被篡改。
而HMAC算法就可以用一把發送方和接收方都有的密鑰key進行計算,而沒有這個密鑰key的第三方是無法計算出正确的散列值的,這樣就可以防止資料的來源方被篡改。
總結
HMAC 算法目前的應用場景相對還比較少,通常會直接使用加密算法來保證來源方的正确性,不過HMAC在特定場景下還是有一定用途的,大家可以根據自己的業務特點來選擇使用哪種加密算法。
文章來源:https://zhuanlan.zhihu.com/p/344092294