1、简述
mac(Message Authentication Code,消息认证码算法)是含有密钥散列函数算法,兼容了MD和SHA算法的特性,并在此基础上加上了密钥。因此MAC算法也经常被称作 HMAC算法。注意,经过mac算法得到的摘要值也可以使用十六进制编码表示,其摘要值得长度与实现算法的摘要值长度相同。例如 HmacSHA算法得到的摘要长度就是SHA1算法得到的摘要长度,都是160位二进制数,换算成十六进制的编码为40位。
2、模型分析
甲乙双方进行数据交换可以采取如下流程:
(1)、 甲方向乙方公布摘要算法(就是指定要使用的摘要算法名)
(2)、甲乙双方按照约定构造密钥,双方拥有相同的密钥(一般是一方构造密钥后通知另外一方,此过程不需要通过程序实现,就是双方约定个字符串,但是这个字符串可不是随便设定的,也是通过相关算法获取的)
(3)、甲方使用密钥对消息做摘要处理,然后将(2)生成的密钥和生成的摘要消息一同发送给乙方
(4)、乙方收到消息后,使用甲方已经公布的摘要算法+约定好的密钥 对收到的消息进行摘要处理。然后比对自己的摘要消息和甲方发过来的摘要消息。甄别消息是否是甲方发送过来的。
3、实现
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
/**
* sun 自带的
*/
public class MACCoder1 {
/**
* 初始化HmacMD5的密钥
* @return byte[] 密钥
*/
public static byte[] initHmacMD5Key(){
try {
//1、初始化 KeyGenerator
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
//2、产生密钥
SecretKey secretKey = keyGenerator.generateKey();
//3、获取密钥
byte[] b = secretKey.getEncoded();
return b;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* HmacMD5消息摘要
* @param data 待做摘要处理的数据
* @param key 密钥
* @return byte[] 消息摘要
* */
public static byte[] encodeHmacMD5(byte[] data, byte[] key){
try {
//还原密钥,因为密钥是以byte形式为消息传递算法所拥有
SecretKey secretKey = new SecretKeySpec(key, "HmacMD5");
//实例化 mac
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
//初始化Mac 密钥
mac.init(secretKey);
//执行消息摘要处理
return mac.doFinal(data);
} catch (NoSuchAlgorithmException e){
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) throws Exception {
String source = "mac 测试";
byte[] key = initHmacMD5Key();
byte[] ss = encodeHmacMD5(source.getBytes("utf-8"),key);
System.out.println("md5 生成的 key:" + key);
System.out.println("md5 加密后的消息:" + bytes2HexString(ss));
System.out.println("-------------------------------------");
key = initHmacSHA256Key();
ss = encodeHmacSHA256(source.getBytes("utf-8"), key);
System.out.println("SHA256 生成的 key:" + key);
System.out.println("SHA256 加密后的消息:" + bytes2HexString(ss));
/***Console 结果
* md5 生成的 key:[B@73995d80
md5 加密后的消息:02B0744A0BDAAD671324BE6BB411A31C
-------------------------------------
SHA256 生成的 key:[B@33bfc93a
SHA256 加密后的消息:41AC24A928A9CFF77670FC8020DCA73ED7352364DA939162B0DFCCE6A4ECCB89
*/
}
/**
*把字节数组转换为16进制的形式
* @param b
* @return
*/
public static String bytes2HexString(byte[] b) {
String ret = "";
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[ i ] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
ret += hex.toUpperCase();
}
return ret;
}
/**
* 初始化HmacSHA256的密钥
* @return byte[] 密钥
*/
public static byte[] initHmacSHA256Key(){
try {
//1、初始化 KeyGenerator
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA256");
//2、产生密钥
SecretKey secretKey = keyGenerator.generateKey();
//3、获取密钥
byte[] b = secretKey.getEncoded();
return b;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* HmacSHA256消息摘要
* @param data 待做摘要处理的数据
* @param key 密钥
* @return byte[] 消息摘要
* */
public static byte[] encodeHmacSHA256(byte[] data, byte[] key){
try {
//还原密钥,因为密钥是以byte形式为消息传递算法所拥有
SecretKey secretKey = new SecretKeySpec(key, "HmacSHA256");
//实例化 mac
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
//初始化Mac 密钥
mac.init(secretKey);
//执行消息摘要处理
return mac.doFinal(data);
} catch (NoSuchAlgorithmException e){
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
}
4、小结
(1)、sun支持了5中算法,但是不支持转成16进制,但是可以用commons codec或者bouncycastle的16进制转换协助进行转换
(2)、bouncycastle支持补充了三种算法,并支持16进制转换