注意:本节内容主要参考自《Java加密与解密的艺术(第2版)》第6章“验证数据完整性--消息摘要算法”
5.1、mac(又称为Hmac)
原理:在md与sha系列算法的基础上加入了密钥,是三大常用的消息摘要算法中最安全的一个。
常用的mac算法:
5.2、实现方式
5.2.1、基于JDK实现的Hmac系列算法
1 package com.util.mac; 2 3 import java.io.UnsupportedEncodingException; 4 import java.security.InvalidKeyException; 5 import java.security.NoSuchAlgorithmException; 6 7 import javax.crypto.KeyGenerator; 8 import javax.crypto.Mac; 9 import javax.crypto.SecretKey; 10 import javax.crypto.spec.SecretKeySpec; 11 12 import org.bouncycastle.util.encoders.Hex; 13 14 /** 15 * 基于JDK的HmacMD5算法 16 */ 17 public class HmacMD5JDK { 18 private static final String ENCODING = "UTF-8"; 19 private static final String ALGORITHM = "HmacMD5";//指定具体算法HmacMD5,HmacSHA1,HmacSHA256 20 21 /** 22 * 产生密钥两种方式 1)是由jdk自己来产生的,2)我们可以自己指定一个字节数组 23 * 注意:密钥是以二进制字节数组存储的 24 */ 25 public static byte[] getKey() throws NoSuchAlgorithmException{ 26 SecretKey key = KeyGenerator.getInstance(ALGORITHM).generateKey(); 27 return key.getEncoded(); 28 } 29 30 /** 31 * HmacMD5加密 32 * @param data 带加密数据 33 * @param keyByte 密钥 34 */ 35 public static byte[] encode(String data, byte[] keyByte) throws NoSuchAlgorithmException, 36 InvalidKeyException, 37 IllegalStateException, 38 UnsupportedEncodingException { 39 SecretKey key = new SecretKeySpec(keyByte, ALGORITHM);//还原密钥 40 Mac mac = Mac.getInstance(key.getAlgorithm()); 41 mac.init(key);//为mac实例初始化密钥 42 return mac.doFinal(data.getBytes(ENCODING)); 43 } 44 45 /** 46 * HmacMD5加密,并转为16进制 47 */ 48 public static String encodeHmacMD5Hex(String data, byte[] keyByte) throws NoSuchAlgorithmException, 49 UnsupportedEncodingException, 50 InvalidKeyException, 51 IllegalStateException { 52 byte[] encodedByte = encode(data, keyByte); 53 return new String(Hex.encode(encodedByte));//借助BC 54 //return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC 55 } 56 57 /** 58 * 测试 59 * @throws IllegalStateException 60 * @throws InvalidKeyException 61 */ 62 public static void main(String[] args) throws UnsupportedEncodingException, 63 NoSuchAlgorithmException, 64 InvalidKeyException, 65 IllegalStateException { 66 String data = "找一个好姑娘做老婆是我的梦 想!"; 67 /*************测试encode()**************/ 68 System.out.println("原文-->"+data); 69 byte[] keyByte = HmacMD5JDK.getKey(); 70 byte[] encodedByte = HmacMD5JDK.encode(data, keyByte); 71 System.out.println("加密后-->"+encodedByte); 72 byte[] encodedByte2 = HmacMD5JDK.encode(data, keyByte); 73 System.out.println("加密后-->"+encodedByte2); 74 for(int i=0;i<encodedByte.length;i++){ 75 System.out.println(encodedByte[i]==encodedByte2[i]); 76 } 77 /*************测试encodeHmacMD5Hex()**************/ 78 System.out.println("原文-->"+data); 79 String encodedStr = HmacMD5JDK.encodeHmacMD5Hex(data, keyByte); 80 System.out.println("加密后-->"+encodedStr); 81 String encodedStr2 = HmacMD5JDK.encodeHmacMD5Hex(data, keyByte); 82 System.out.println("加密后-->"+encodedStr2); 83 System.out.println(encodedStr.equals(encodedStr2)); 84 } 85 }
注意几点:
5.2.1、基于CC实现的Hmac系列算法
1 package com.util.mac; 2 3 import java.io.UnsupportedEncodingException; 4 import java.security.InvalidKeyException; 5 import java.security.NoSuchAlgorithmException; 6 7 import org.apache.commons.codec.DecoderException; 8 import org.apache.commons.codec.binary.Hex; 9 import org.apache.commons.codec.digest.HmacUtils; 10 11 /** 12 * 基于CC的HmacMD5算法 13 */ 14 public class HmacMD5CC { 15 private static final String ENCODING = "UTF-8"; 16 /** 17 * 产生密钥 18 */ 19 public static byte[] getKey() throws NoSuchAlgorithmException, DecoderException{ 20 return Hex.decodeHex(new char[]{'a','b','c','d'}); 21 } 22 23 /** 24 * HmacMD5加密 25 * @param data 带加密数据 26 * @param keyByte 密钥 27 */ 28 public static byte[] encode(String data, byte[] keyByte) throws NoSuchAlgorithmException, 29 InvalidKeyException, 30 IllegalStateException, 31 UnsupportedEncodingException { 32 return HmacUtils.hmacMd5(keyByte, data.getBytes(ENCODING)); 33 } 34 35 /** 36 * HmacMD5加密,并转为16进制 37 */ 38 public static String encodeHmacMD5Hex(String data, byte[] keyByte) throws NoSuchAlgorithmException, 39 UnsupportedEncodingException, 40 InvalidKeyException, 41 IllegalStateException { 42 return HmacUtils.hmacMd5Hex(keyByte, data.getBytes(ENCODING)); 43 } 44 45 /** 46 * 测试 47 * @throws IllegalStateException 48 * @throws InvalidKeyException 49 * @throws DecoderException 50 */ 51 public static void main(String[] args) throws UnsupportedEncodingException, 52 NoSuchAlgorithmException, 53 InvalidKeyException, 54 IllegalStateException, 55 DecoderException { 56 String data = "找一个好姑娘做老婆是我的梦 想!"; 57 /*************测试encode()**************/ 58 System.out.println("原文-->"+data); 59 byte[] keyByte = HmacMD5CC.getKey(); 60 byte[] encodedByte = HmacMD5CC.encode(data, keyByte); 61 System.out.println("加密后-->"+encodedByte); 62 byte[] encodedByte2 = HmacMD5CC.encode(data, keyByte); 63 System.out.println("加密后-->"+encodedByte2); 64 for(int i=0;i<encodedByte.length;i++){ 65 System.out.println(encodedByte[i]==encodedByte2[i]); 66 } 67 /*************测试encodeHmacMD5Hex()**************/ 68 System.out.println("原文-->"+data); 69 String encodedStr = HmacMD5CC.encodeHmacMD5Hex(data, keyByte); 70 System.out.println("加密后-->"+encodedStr); 71 String encodedStr2 = HmacMD5CC.encodeHmacMD5Hex(data, keyByte); 72 System.out.println("加密后-->"+encodedStr2); 73 System.out.println(encodedStr.equals(encodedStr2)); 74 } 75 }
注意:
CC API文档: