一、簡述
mac(Message Authentication Code,訊息認證碼演算法)是含有密鑰散列函數演算法,相容了MD和SHA演算法的特性,並在此基礎上加上了密鑰。因此MAC演算法也經常被稱作HMAC演算法。關於hmac演算法的詳情可以參看RFC 2104(http://www.ietf.org/rfc/rfc2104.txt),這裡包含了HmacMD5演算法的C語言實現。
這裡需要說明的是經過mac演算法得到的摘要值也可以使用十六進位編碼錶示,其摘要值得長度與實現演算法的摘要值長度相同。例如 HmacSHA演算法得到的摘要長度就是SHA1演算法得到的摘要長度,都是160位位元,換算成十六進位的編碼為40位。
二、模型分析
甲乙雙方進行資料交換可以採取如下流程完成
1、甲方向乙方公布摘要演算法(就是指定要使用的摘要演算法名)
2、甲乙雙方按照約定構造密鑰,雙方擁有相同的密鑰(一般是一方構造密鑰後通知另外一方,此過程不需要通過程式實現,就是雙方約定個字串,但是這個字串可不是隨便設定的,也是通過相關演算法擷取的)
3、甲方使用金鑰組訊息做摘要處理,然後將訊息和產生的摘要訊息一同發送給乙方
4、乙方收到訊息後,使用甲方已經公布的摘要演算法+約定好的密鑰 對收到的訊息進行摘要處理。然後比對自己的摘要訊息和甲方發過來的摘要訊息。甄別訊息是否是甲方發送過來的
三、MAC系列演算法支援表
| 演算法 |
摘要長度 |
備忘 |
| HmacMD5 |
128 |
JAVA6實現 |
| HmacSHA1 |
160 |
JAVA6實現 |
| HmacSHA256 |
256 |
JAVA6實現 |
| HmacSHA384 |
384 |
JAVA6實現 |
| HmacSHA512 |
512 |
JAVA6實現 |
| HmacMD2 |
128 |
BouncyCastle實現 |
| HmacMD4 |
128 |
BouncyCastle實現 |
| HmacSHA224 |
224 |
BouncyCastle實現 |
四、sun以及bouncycastle的hmac演算法實現
package com.ca.test;<br />import java.security.Security;<br />import javax.crypto.KeyGenerator;<br />import javax.crypto.Mac;<br />import javax.crypto.SecretKey;<br />import javax.crypto.spec.SecretKeySpec;<br />import org.bouncycastle.jce.provider.BouncyCastleProvider;<br />import org.bouncycastle.util.encoders.Hex;<br />/**<br /> * MAC訊息摘要組件<br /> * @author kongqz<br /> * */<br />public class MACCoder {<br />///////////////////////////HmacMD5///////////////////////////////<br />/**<br /> * 初始化HmacMD5的密鑰<br /> * @return byte[] 密鑰<br /> *<br /> * */<br />public static byte[] initHmacMD5Key() throws Exception{<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD5");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacMD5訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacMD5(byte[] data,byte[] key) throws Exception{<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacMD5");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}</p><p>///////////////////////////////HmacSHA1//////////////////////////////////<br />/**<br /> * 初始化HmacSHA1的密鑰<br /> * @return byte[] 密鑰<br /> *<br /> * */<br />public static byte[] initHmacSHAKey() throws Exception{<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA1");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacSHA1訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacSHA(byte[] data,byte[] key) throws Exception{<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacSHA1");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}</p><p>///////////////////////////////HmacSHA256//////////////////////////////////<br />/**<br /> * 初始化HmacSHA256的密鑰<br /> * @return byte[] 密鑰<br /> *<br /> * */<br />public static byte[] initHmacSHA256Key() throws Exception{<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA256");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacSHA256訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacSHA256(byte[] data,byte[] key) throws Exception{<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacSHA256");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}</p><p>///////////////////////////////HmacSHA384//////////////////////////////////<br />/**<br /> * 初始化HmacSHA384的密鑰<br /> * @return byte[] 密鑰<br /> *<br /> * */<br />public static byte[] initHmacSHA384Key() throws Exception{<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA384");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacSHA384訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacSHA384(byte[] data,byte[] key) throws Exception{<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacSHA384");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}</p><p>///////////////////////////////HmacSHA512//////////////////////////////////<br />/**<br /> * 初始化HmacSHA512的密鑰<br /> * @return byte[] 密鑰<br /> *<br /> * */<br />public static byte[] initHmacSHA512Key() throws Exception{<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA512");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacSHA512訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacSHA512(byte[] data,byte[] key) throws Exception{<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacSHA512");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}<br />///////////////////////////////HmacMD2-BouncyCastle才支援的實現//////////////////////////////////<br />/**<br /> * 初始化HmacMD2的密鑰<br /> * @return byte[] 密鑰<br /> * */<br />public static byte[] initHmacMD2Key() throws Exception{</p><p>//加入BouncyCastleProvider的支援<br />Security.addProvider(new BouncyCastleProvider());<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD2");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacMD2訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacMD2(byte[] data,byte[] key) throws Exception{<br />//加入BouncyCastleProvider的支援<br />Security.addProvider(new BouncyCastleProvider());<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacMD2");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}<br />/**<br /> * HmacMD2Hex訊息摘要<br /> * @param data 待做訊息摘要處理的資料<br /> * @param String 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static String encodeHmacMD2Hex(byte[] data,byte[] key) throws Exception{<br />//執行訊息摘要處理<br />byte[] b=encodeHmacMD2(data,key);<br />//做十六進位轉換<br />return new String(Hex.encode(b));<br />}</p><p>///////////////////////////////HmacMD4-BouncyCastle才支援的實現//////////////////////////////////<br />/**<br /> * 初始化HmacMD2的密鑰<br /> * @return byte[] 密鑰<br /> * */<br />public static byte[] initHmacMD4Key() throws Exception{</p><p>//加入BouncyCastleProvider的支援<br />Security.addProvider(new BouncyCastleProvider());<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD4");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacMD4訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacMD4(byte[] data,byte[] key) throws Exception{<br />//加入BouncyCastleProvider的支援<br />Security.addProvider(new BouncyCastleProvider());<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacMD4");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}<br />/**<br /> * HmacMD4Hex訊息摘要<br /> * @param data 待做訊息摘要處理的資料<br /> * @param String 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static String encodeHmacMD4Hex(byte[] data,byte[] key) throws Exception{<br />//執行訊息摘要處理<br />byte[] b=encodeHmacMD4(data,key);<br />//做十六進位轉換<br />return new String(Hex.encode(b));<br />}<br />///////////////////////////////HmacSHA224-BouncyCastle才支援的實現//////////////////////////////////<br />/**<br /> * 初始化HmacSHA224的密鑰<br /> * @return byte[] 密鑰<br /> * */<br />public static byte[] initHmacSHA224Key() throws Exception{</p><p>//加入BouncyCastleProvider的支援<br />Security.addProvider(new BouncyCastleProvider());<br />//初始化KeyGenerator<br />KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA224");<br />//產生密鑰<br />SecretKey secretKey=keyGenerator.generateKey();<br />//擷取密鑰<br />return secretKey.getEncoded();<br />}<br />/**<br /> * HmacSHA224訊息摘要<br /> * @param data 待做摘要處理的資料<br /> * @param key 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static byte[] encodeHmacSHA224(byte[] data,byte[] key) throws Exception{<br />//加入BouncyCastleProvider的支援<br />Security.addProvider(new BouncyCastleProvider());<br />//還原密鑰,因為密鑰是以byte形式為訊息傳遞演算法所擁有<br />SecretKey secretKey=new SecretKeySpec(key,"HmacSHA224");<br />//執行個體化Mac<br />Mac mac=Mac.getInstance(secretKey.getAlgorithm());<br />//初始化Mac<br />mac.init(secretKey);<br />//執行訊息摘要處理<br />return mac.doFinal(data);<br />}<br />/**<br /> * HmacSHA224Hex訊息摘要<br /> * @param data 待做訊息摘要處理的資料<br /> * @param String 密鑰<br /> * @return byte[] 訊息摘要<br /> * */<br />public static String encodeHmacSHA224Hex(byte[] data,byte[] key) throws Exception{<br />//執行訊息摘要處理<br />byte[] b=encodeHmacSHA224(data,key);<br />//做十六進位轉換<br />return new String(Hex.encode(b));<br />}<br />/**<br /> * 進行相關的摘要演算法的處理展示<br /> * @throws Exception<br /> * **/<br />public static void main(String[] args) throws Exception {<br />String str="HmacMD5訊息摘要";<br />//初始化密鑰<br />byte[] key1=MACCoder.initHmacMD5Key();<br />//擷取摘要資訊<br />byte[] data1=MACCoder.encodeHmacMD5(str.getBytes(), key1);</p><p>System.out.println("原文:"+str);<br />System.out.println();<br />System.out.println("HmacMD5的密鑰:"+key1.toString());<br />System.out.println("HmacMD5演算法摘要:"+data1.toString());<br />System.out.println();</p><p>//初始化密鑰<br />byte[] key2=MACCoder.initHmacSHA256Key();<br />//擷取摘要資訊<br />byte[] data2=MACCoder.encodeHmacSHA256(str.getBytes(), key2);<br />System.out.println("HmacSHA256的密鑰:"+key2.toString());<br />System.out.println("HmacSHA256演算法摘要:"+data2.toString());<br />System.out.println();</p><p>//初始化密鑰<br />byte[] key3=MACCoder.initHmacSHAKey();<br />//擷取摘要資訊<br />byte[] data3=MACCoder.encodeHmacSHA(str.getBytes(), key3);<br />System.out.println("HmacSHA1的密鑰:"+key3.toString());<br />System.out.println("HmacSHA1演算法摘要:"+data3.toString());<br />System.out.println();</p><p>//初始化密鑰<br />byte[] key4=MACCoder.initHmacSHA384Key();<br />//擷取摘要資訊<br />byte[] data4=MACCoder.encodeHmacSHA384(str.getBytes(), key4);<br />System.out.println("HmacSHA384的密鑰:"+key4.toString());<br />System.out.println("HmacSHA384演算法摘要:"+data4.toString());<br />System.out.println();</p><p>//初始化密鑰<br />byte[] key5=MACCoder.initHmacSHA512Key();<br />//擷取摘要資訊<br />byte[] data5=MACCoder.encodeHmacSHA512(str.getBytes(), key5);<br />System.out.println("HmacSHA512的密鑰:"+key5.toString());<br />System.out.println("HmacSHA512演算法摘要:"+data5.toString());<br />System.out.println();</p><p>System.out.println("================以下的演算法支援是bouncycastle支援的演算法,sun java6不支援=======================");<br />//初始化密鑰<br />byte[] key6=MACCoder.initHmacMD2Key();<br />//擷取摘要資訊<br />byte[] data6=MACCoder.encodeHmacMD2(str.getBytes(), key6);<br />String datahex6=MACCoder.encodeHmacMD2Hex(str.getBytes(), key6);<br />System.out.println("Bouncycastle HmacMD2的密鑰:"+key6.toString());<br />System.out.println("Bouncycastle HmacMD2演算法摘要:"+data6.toString());<br />System.out.println("Bouncycastle HmacMD2Hex演算法摘要:"+datahex6.toString());<br />System.out.println();</p><p>//初始化密鑰<br />byte[] key7=MACCoder.initHmacMD4Key();<br />//擷取摘要資訊<br />byte[] data7=MACCoder.encodeHmacMD4(str.getBytes(), key7);<br />String datahex7=MACCoder.encodeHmacMD4Hex(str.getBytes(), key7);<br />System.out.println("Bouncycastle HmacMD4的密鑰:"+key7.toString());<br />System.out.println("Bouncycastle HmacMD4演算法摘要:"+data7.toString());<br />System.out.println("Bouncycastle HmacMD4Hex演算法摘要:"+datahex7.toString());<br />System.out.println();</p><p>//初始化密鑰<br />byte[] key8=MACCoder.initHmacSHA224Key();<br />//擷取摘要資訊<br />byte[] data8=MACCoder.encodeHmacSHA224(str.getBytes(), key8);<br />String datahex8=MACCoder.encodeHmacSHA224Hex(str.getBytes(), key8);<br />System.out.println("Bouncycastle HmacSHA224的密鑰:"+key8.toString());<br />System.out.println("Bouncycastle HmacSHA224演算法摘要:"+data8.toString());<br />System.out.println("Bouncycastle HmacSHA224演算法摘要:"+datahex8.toString());<br />System.out.println();<br />}<br />}<br />控制台輸出結果如下:<br />原文:HmacMD5訊息摘要<br />HmacMD5的密鑰:[B@136228<br />HmacMD5演算法摘要:[B@913750<br />HmacSHA256的密鑰:[B@bfbdb0<br />HmacSHA256演算法摘要:[B@3e86d0<br />HmacSHA1的密鑰:[B@253498<br />HmacSHA1演算法摘要:[B@9fef6f<br />HmacSHA384的密鑰:[B@f38798<br />HmacSHA384演算法摘要:[B@4b222f<br />HmacSHA512的密鑰:[B@b0f13d<br />HmacSHA512演算法摘要:[B@ae000d<br />================以下的演算法支援是bouncycastle支援的演算法,sun java6不支援=======================<br />Bouncycastle HmacMD2的密鑰:[B@4741d6<br />Bouncycastle HmacMD2演算法摘要:[B@337d0f<br />Bouncycastle HmacMD2Hex演算法摘要:0fbabb3bb1a2be81fbc823013f6920fe<br />Bouncycastle HmacMD4的密鑰:[B@1e0bc08<br />Bouncycastle HmacMD4演算法摘要:[B@158b649<br />Bouncycastle HmacMD4Hex演算法摘要:a3fa5935ca554f83c8987efd2bcfe605<br />Bouncycastle HmacSHA224的密鑰:[B@8a0d5d<br />Bouncycastle HmacSHA224演算法摘要:[B@173831b<br />Bouncycastle HmacSHA224演算法摘要:542d47250e5ff9f8bb3a7607799b1685a8accd65580410ea1d4dd578<br />
五、總結
1、sun支援了5中演算法,但是不支援轉成16進位,但是可以用commons codec或者bouncycastle的16進位轉換協助進行轉換
2、bouncycastle支援補充了三種演算法,並支援16進位轉換