原文:http://blog.youkuaiyun.com/kongqz/article/details/6281710
一、简述
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;
- import java.security.Security;
- import javax.crypto.KeyGenerator;
- import javax.crypto.Mac;
- import javax.crypto.SecretKey;
- import javax.crypto.spec.SecretKeySpec;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- import org.bouncycastle.util.encoders.Hex;
- /**
- * MAC消息摘要组件
- * @author kongqz
- * */
- public class MACCoder {
- ///HmacMD5///
- /**
- * 初始化HmacMD5的密钥
- * @return byte[] 密钥
- *
- * */
- public static byte[] initHmacMD5Key() throws Exception{
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD5");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacMD5消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacMD5(byte[] data,byte[] key) throws Exception{
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacMD5");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- ///HmacSHA1//
- /**
- * 初始化HmacSHA1的密钥
- * @return byte[] 密钥
- *
- * */
- public static byte[] initHmacSHAKey() throws Exception{
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA1");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacSHA1消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacSHA(byte[] data,byte[] key) throws Exception{
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacSHA1");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- ///HmacSHA256//
- /**
- * 初始化HmacSHA256的密钥
- * @return byte[] 密钥
- *
- * */
- public static byte[] initHmacSHA256Key() throws Exception{
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA256");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacSHA256消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacSHA256(byte[] data,byte[] key) throws Exception{
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacSHA256");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- ///HmacSHA384//
- /**
- * 初始化HmacSHA384的密钥
- * @return byte[] 密钥
- *
- * */
- public static byte[] initHmacSHA384Key() throws Exception{
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA384");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacSHA384消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacSHA384(byte[] data,byte[] key) throws Exception{
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacSHA384");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- ///HmacSHA512//
- /**
- * 初始化HmacSHA512的密钥
- * @return byte[] 密钥
- *
- * */
- public static byte[] initHmacSHA512Key() throws Exception{
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA512");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacSHA512消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacSHA512(byte[] data,byte[] key) throws Exception{
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacSHA512");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- ///HmacMD2-BouncyCastle才支持的实现//
- /**
- * 初始化HmacMD2的密钥
- * @return byte[] 密钥
- * */
- public static byte[] initHmacMD2Key() throws Exception{
- //加入BouncyCastleProvider的支持
- Security.addProvider(new BouncyCastleProvider());
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD2");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacMD2消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacMD2(byte[] data,byte[] key) throws Exception{
- //加入BouncyCastleProvider的支持
- Security.addProvider(new BouncyCastleProvider());
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacMD2");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- /**
- * HmacMD2Hex消息摘要
- * @param data 待做消息摘要处理的数据
- * @param String 密钥
- * @return byte[] 消息摘要
- * */
- public static String encodeHmacMD2Hex(byte[] data,byte[] key) throws Exception{
- //执行消息摘要处理
- byte[] b=encodeHmacMD2(data,key);
- //做十六进制转换
- return new String(Hex.encode(b));
- }
- ///HmacMD4-BouncyCastle才支持的实现//
- /**
- * 初始化HmacMD2的密钥
- * @return byte[] 密钥
- * */
- public static byte[] initHmacMD4Key() throws Exception{
- //加入BouncyCastleProvider的支持
- Security.addProvider(new BouncyCastleProvider());
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacMD4");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacMD4消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacMD4(byte[] data,byte[] key) throws Exception{
- //加入BouncyCastleProvider的支持
- Security.addProvider(new BouncyCastleProvider());
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacMD4");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- /**
- * HmacMD4Hex消息摘要
- * @param data 待做消息摘要处理的数据
- * @param String 密钥
- * @return byte[] 消息摘要
- * */
- public static String encodeHmacMD4Hex(byte[] data,byte[] key) throws Exception{
- //执行消息摘要处理
- byte[] b=encodeHmacMD4(data,key);
- //做十六进制转换
- return new String(Hex.encode(b));
- }
- ///HmacSHA224-BouncyCastle才支持的实现//
- /**
- * 初始化HmacSHA224的密钥
- * @return byte[] 密钥
- * */
- public static byte[] initHmacSHA224Key() throws Exception{
- //加入BouncyCastleProvider的支持
- Security.addProvider(new BouncyCastleProvider());
- //初始化KeyGenerator
- KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacSHA224");
- //产生密钥
- SecretKey secretKey=keyGenerator.generateKey();
- //获取密钥
- return secretKey.getEncoded();
- }
- /**
- * HmacSHA224消息摘要
- * @param data 待做摘要处理的数据
- * @param key 密钥
- * @return byte[] 消息摘要
- * */
- public static byte[] encodeHmacSHA224(byte[] data,byte[] key) throws Exception{
- //加入BouncyCastleProvider的支持
- Security.addProvider(new BouncyCastleProvider());
- //还原密钥,因为密钥是以byte形式为消息传递算法所拥有
- SecretKey secretKey=new SecretKeySpec(key,"HmacSHA224");
- //实例化Mac
- Mac mac=Mac.getInstance(secretKey.getAlgorithm());
- //初始化Mac
- mac.init(secretKey);
- //执行消息摘要处理
- return mac.doFinal(data);
- }
- /**
- * HmacSHA224Hex消息摘要
- * @param data 待做消息摘要处理的数据
- * @param String 密钥
- * @return byte[] 消息摘要
- * */
- public static String encodeHmacSHA224Hex(byte[] data,byte[] key) throws Exception{
- //执行消息摘要处理
- byte[] b=encodeHmacSHA224(data,key);
- //做十六进制转换
- return new String(Hex.encode(b));
- }
- /**
- * 进行相关的摘要算法的处理展示
- * @throws Exception
- * **/
- public static void main(String[] args) throws Exception {
- String str="HmacMD5消息摘要";
- //初始化密钥
- byte[] key1=MACCoder.initHmacMD5Key();
- //获取摘要信息
- byte[] data1=MACCoder.encodeHmacMD5(str.getBytes(), key1);
- System.out.println("原文:"+str);
- System.out.println();
- System.out.println("HmacMD5的密钥:"+key1.toString());
- System.out.println("HmacMD5算法摘要:"+data1.toString());
- System.out.println();
- //初始化密钥
- byte[] key2=MACCoder.initHmacSHA256Key();
- //获取摘要信息
- byte[] data2=MACCoder.encodeHmacSHA256(str.getBytes(), key2);
- System.out.println("HmacSHA256的密钥:"+key2.toString());
- System.out.println("HmacSHA256算法摘要:"+data2.toString());
- System.out.println();
- //初始化密钥
- byte[] key3=MACCoder.initHmacSHAKey();
- //获取摘要信息
- byte[] data3=MACCoder.encodeHmacSHA(str.getBytes(), key3);
- System.out.println("HmacSHA1的密钥:"+key3.toString());
- System.out.println("HmacSHA1算法摘要:"+data3.toString());
- System.out.println();
- //初始化密钥
- byte[] key4=MACCoder.initHmacSHA384Key();
- //获取摘要信息
- byte[] data4=MACCoder.encodeHmacSHA384(str.getBytes(), key4);
- System.out.println("HmacSHA384的密钥:"+key4.toString());
- System.out.println("HmacSHA384算法摘要:"+data4.toString());
- System.out.println();
- //初始化密钥
- byte[] key5=MACCoder.initHmacSHA512Key();
- //获取摘要信息
- byte[] data5=MACCoder.encodeHmacSHA512(str.getBytes(), key5);
- System.out.println("HmacSHA512的密钥:"+key5.toString());
- System.out.println("HmacSHA512算法摘要:"+data5.toString());
- System.out.println();
- System.out.println("================以下的算法支持是bouncycastle支持的算法,sun java6不支持=======================");
- //初始化密钥
- byte[] key6=MACCoder.initHmacMD2Key();
- //获取摘要信息
- byte[] data6=MACCoder.encodeHmacMD2(str.getBytes(), key6);
- String datahex6=MACCoder.encodeHmacMD2Hex(str.getBytes(), key6);
- System.out.println("Bouncycastle HmacMD2的密钥:"+key6.toString());
- System.out.println("Bouncycastle HmacMD2算法摘要:"+data6.toString());
- System.out.println("Bouncycastle HmacMD2Hex算法摘要:"+datahex6.toString());
- System.out.println();
- //初始化密钥
- byte[] key7=MACCoder.initHmacMD4Key();
- //获取摘要信息
- byte[] data7=MACCoder.encodeHmacMD4(str.getBytes(), key7);
- String datahex7=MACCoder.encodeHmacMD4Hex(str.getBytes(), key7);
- System.out.println("Bouncycastle HmacMD4的密钥:"+key7.toString());
- System.out.println("Bouncycastle HmacMD4算法摘要:"+data7.toString());
- System.out.println("Bouncycastle HmacMD4Hex算法摘要:"+datahex7.toString());
- System.out.println();
- //初始化密钥
- byte[] key8=MACCoder.initHmacSHA224Key();
- //获取摘要信息
- byte[] data8=MACCoder.encodeHmacSHA224(str.getBytes(), key8);
- String datahex8=MACCoder.encodeHmacSHA224Hex(str.getBytes(), key8);
- System.out.println("Bouncycastle HmacSHA224的密钥:"+key8.toString());
- System.out.println("Bouncycastle HmacSHA224算法摘要:"+data8.toString());
- System.out.println("Bouncycastle HmacSHA224算法摘要:"+datahex8.toString());
- System.out.println();
- }
- }
- 控制台输出结果如下:
- 原文:HmacMD5消息摘要
- HmacMD5的密钥:[B@136228
- HmacMD5算法摘要:[B@913750
- HmacSHA256的密钥:[B@bfbdb0
- HmacSHA256算法摘要:[B@3e86d0
- HmacSHA1的密钥:[B@253498
- HmacSHA1算法摘要:[B@9fef6f
- HmacSHA384的密钥:[B@f38798
- HmacSHA384算法摘要:[B@4b222f
- HmacSHA512的密钥:[B@b0f13d
- HmacSHA512算法摘要:[B@ae000d
- ================以下的算法支持是bouncycastle支持的算法,sun java6不支持=======================
- Bouncycastle HmacMD2的密钥:[B@4741d6
- Bouncycastle HmacMD2算法摘要:[B@337d0f
- Bouncycastle HmacMD2Hex算法摘要:0fbabb3bb1a2be81fbc823013f6920fe
- Bouncycastle HmacMD4的密钥:[B@1e0bc08
- Bouncycastle HmacMD4算法摘要:[B@158b649
- Bouncycastle HmacMD4Hex算法摘要:a3fa5935ca554f83c8987efd2bcfe605
- Bouncycastle HmacSHA224的密钥:[B@8a0d5d
- Bouncycastle HmacSHA224算法摘要:[B@173831b
- Bouncycastle HmacSHA224算法摘要:542d47250e5ff9f8bb3a7607799b1685a8accd65580410ea1d4dd578
五、总结
1、sun支持了5中算法,但是不支持转成16进制,但是可以用commons codec或者bouncycastle的16进制转换协助进行转换
2、bouncycastle支持补充了三种算法,并支持16进制转换