您的位置:首页 > 其它

第五章 消息摘要算法--MAC

2015-12-29 12:48 330 查看
[b]注意:本节内容主要参考自《Java加密与解密的艺术(第2版)》第6章“验证数据完整性--消息摘要算法”[/b]

5.1、mac(又称为Hmac)

原理:在md与sha系列算法的基础上加入了密钥,是三大常用的消息摘要算法中最安全的一个。

常用的mac算法:

HmacMD5

HmacSHA1

HmacSHA256

5.2、实现方式

JDK(缺少二进制字节数组转十六进制的工具,可借助CC或BC的工具类完成)

Commons Codec(CC,在1.10版本中加入的,其中,产生相应算法密钥的API没有找到,如果有人找到了,请和我讲一下,谢谢

Bouncy Castle(BC,比较麻烦,具体参考“慕课网”)

5.2.1、基于JDK实现的Hmac系列算法

package com.util.mac;

import java.io.UnsupportedEncodingException;
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;

import org.bouncycastle.util.encoders.Hex;

/**
* 基于JDK的HmacMD5算法
*/
public class HmacMD5JDK {
private static final String ENCODING = "UTF-8";
private static final String ALGORITHM = "HmacMD5";//指定具体算法HmacMD5,HmacSHA1,HmacSHA256

/**
* 产生密钥两种方式 1)是由jdk自己来产生的,2)我们可以自己指定一个字节数组
* 注意:密钥是以二进制字节数组存储的
*/
public static byte[] getKey() throws NoSuchAlgorithmException{
SecretKey key = KeyGenerator.getInstance(ALGORITHM).generateKey();
return key.getEncoded();
}

/**
* HmacMD5加密
* @param data     带加密数据
* @param keyByte  密钥
*/
public static byte[] encode(String data, byte[] keyByte) throws NoSuchAlgorithmException,
InvalidKeyException,
IllegalStateException,
UnsupportedEncodingException {
SecretKey key = new SecretKeySpec(keyByte, ALGORITHM);//还原密钥
Mac mac = Mac.getInstance(key.getAlgorithm());
mac.init(key);//为mac实例初始化密钥
return mac.doFinal(data.getBytes(ENCODING));
}

/**
* HmacMD5加密,并转为16进制
*/
public static String encodeHmacMD5Hex(String data, byte[] keyByte) throws NoSuchAlgorithmException,
UnsupportedEncodingException,
InvalidKeyException,
IllegalStateException {
byte[] encodedByte = encode(data, keyByte);
return new String(Hex.encode(encodedByte));//借助BC
//return new String(org.apache.commons.codec.binary.Hex.encodeHexString(encodedByte));//借助CC
}

/**
* 测试
* @throws IllegalStateException
* @throws InvalidKeyException
*/
public static void main(String[] args) throws UnsupportedEncodingException,
NoSuchAlgorithmException,
InvalidKeyException,
IllegalStateException {
String data = "找一个好姑娘做老婆是我的梦 想!";
/*************测试encode()**************/
System.out.println("原文-->"+data);
byte[] keyByte = HmacMD5JDK.getKey();
byte[] encodedByte = HmacMD5JDK.encode(data, keyByte);
System.out.println("加密后-->"+encodedByte);
byte[] encodedByte2 = HmacMD5JDK.encode(data, keyByte);
System.out.println("加密后-->"+encodedByte2);
for(int i=0;i<encodedByte.length;i++){
System.out.println(encodedByte[i]==encodedByte2[i]);
}
/*************测试encodeHmacMD5Hex()**************/
System.out.println("原文-->"+data);
String encodedStr = HmacMD5JDK.encodeHmacMD5Hex(data, keyByte);
System.out.println("加密后-->"+encodedStr);
String encodedStr2 = HmacMD5JDK.encodeHmacMD5Hex(data, keyByte);
System.out.println("加密后-->"+encodedStr2);
System.out.println(encodedStr.equals(encodedStr2));
}
}


注意几点:

产生密钥两种方式:1)直接使用JDK的类(如上边代码所示)2)自己指定字节数组(参考5.2.1)

密钥是一个二进制数组,当然为了提高可读性,可以使用Base64加密后,在传递可对方

在实际使用中,我们可以将密钥产生后,发送者通过安全途径(线下传递等)传给接收方。

在上述的测试中,去测一下同一个消息在使用同一个密钥的情况下,多次mac后结果是否相同。

想切换算法,只需要修改ALGORITHM常数即可,当然如果在实际项目中需要用到多种算法,并且需要实现平滑切换,可以采用策略模式,这个以后会再讲。

5.2.1、基于CC实现的Hmac系列算法

package com.util.mac;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.HmacUtils;

/**
* 基于CC的HmacMD5算法
*/
public class HmacMD5CC {
private static final String ENCODING = "UTF-8";
/**
* 产生密钥
*/
public static byte[] getKey() throws NoSuchAlgorithmException, DecoderException{
return Hex.decodeHex(new char[]{'a','b','c','d'});
}

/**
* HmacMD5加密
* @param data     带加密数据
* @param keyByte  密钥
*/
public static byte[] encode(String data, byte[] keyByte) throws NoSuchAlgorithmException,
InvalidKeyException,
IllegalStateException,
UnsupportedEncodingException {
return HmacUtils.hmacMd5(keyByte, data.getBytes(ENCODING));
}

/**
* HmacMD5加密,并转为16进制
*/
public static String encodeHmacMD5Hex(String data, byte[] keyByte) throws NoSuchAlgorithmException,
UnsupportedEncodingException,
InvalidKeyException,
IllegalStateException {
return HmacUtils.hmacMd5Hex(keyByte, data.getBytes(ENCODING));
}

/**
* 测试
* @throws IllegalStateException
* @throws InvalidKeyException
* @throws DecoderException
*/
public static void main(String[] args) throws UnsupportedEncodingException,
NoSuchAlgorithmException,
InvalidKeyException,
IllegalStateException,
DecoderException {
String data = "找一个好姑娘做老婆是我的梦 想!";
/*************测试encode()**************/
System.out.println("原文-->"+data);
byte[] keyByte = HmacMD5CC.getKey();
byte[] encodedByte = HmacMD5CC.encode(data, keyByte);
System.out.println("加密后-->"+encodedByte);
byte[] encodedByte2 = HmacMD5CC.encode(data, keyByte);
System.out.println("加密后-->"+encodedByte2);
for(int i=0;i<encodedByte.length;i++){
System.out.println(encodedByte[i]==encodedByte2[i]);
}
/*************测试encodeHmacMD5Hex()**************/
System.out.println("原文-->"+data);
String encodedStr = HmacMD5CC.encodeHmacMD5Hex(data, keyByte);
System.out.println("加密后-->"+encodedStr);
String encodedStr2 = HmacMD5CC.encodeHmacMD5Hex(data, keyByte);
System.out.println("加密后-->"+encodedStr2);
System.out.println(encodedStr.equals(encodedStr2));
}
}


注意:

CC很好的封装了jdk的底层,但是CC是在1.10版本中才添加了hmac系列算法

在使用中,若想切换其他算法,只需要调用不同的方法即可,具体的查看本文最下边的CC1.10的API文档链接地址

其中,生成密钥在这里是自己指定了一个字节数组,具体的有CC来产生相应算法的密钥的API并没有看到,如果需要,可以自己去封装,当然,如果在CC中有相应的API,请大家和我讲一下,谢谢!

CC API文档:

[b]http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/HmacUtils.html[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: