java安全(四)HMAC 哈希消息认证
2016-03-21 11:15
513 查看
简述
HMAC(消息认证算法)可以理解就是带有秘钥的的摘要算法,它兼容MD和SHA算法的特性,并在此基础上加入了秘钥。(对摘要算法不了解的可以看我的上一篇博客 这里的摘要算法也是以MD5为例)
原理
算法公式 : HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
H 代表所采用的HASH算法(如MD5)
K 代表认证密码
Ko 代表HASH算法的密文
M 代表一个消息输入
B 代表H中所处理的块大小,这个大小是处理块大小,而不是输出hash的大小
如,SHA-1和SHA-256 B和MD5的 B= 64
SHA-384和SHA-512的 B = 128
L 表示hash的大小 MD5的L=128、SHA-1的L=160。其他的不再一一介绍。
Opad 用0x5c重复B次
Ipad 用0x36重复B次
看到这里好晕呀,那么接下来一MD5作为摘要算法来介绍这个加密算法:
1.K:秘钥 它的长度根据摘要算法处理的数据块B的大小来确定的,这里是64位 若秘钥K的长度不足64位 则需要使用0来补位达到64位,太短的秘钥是不受欢迎的 因为太短了安全性就会降低;若秘钥的长度刚好等于64位 就不用处理了;若秘钥的长度大于64位,则需要先对秘钥做摘要算法计算把结果作为秘钥key。
2.Opad 为重复64次的0x5c 就是64个0x5c组成的串。
3.同理 Ipad 是64个0x36组成的串。
(这里有个疑问 若秘钥长度小于等于64 则秘钥处理后变成长度为64的秘钥 若秘钥长度大于64 则秘钥处理后就变成了长度位128的秘钥 他和ipad和opad是如何做与或运算呢?)
算法需要的材料已备好,开始加密了.
1.用处理好的秘钥和inpad做异或运算 生成S1。
2.将待加密的数据放到S1后面 做摘要算法 这里是MD5摘要 生成H。
3.用处理好的秘钥和Opad做异或运算 生成S2。
4.将第三步的H和S2拼接到一起 用MD5做摘要 生成最终的HMAC的密文。
java代码
典型应用
HMAC的一个典型应用是用在“质疑/应答”(Challenge/Response)身份认证中。
认证流程
(1) 先由客户端向服务器发出一个验证请求。
(2) 服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为质疑)。
(3) 客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。
(4) 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户
HMAC(消息认证算法)可以理解就是带有秘钥的的摘要算法,它兼容MD和SHA算法的特性,并在此基础上加入了秘钥。(对摘要算法不了解的可以看我的上一篇博客 这里的摘要算法也是以MD5为例)
原理
算法公式 : HMAC(K,M)=H(K⊕opad∣H(K⊕ipad∣M))
H 代表所采用的HASH算法(如MD5)
K 代表认证密码
Ko 代表HASH算法的密文
M 代表一个消息输入
B 代表H中所处理的块大小,这个大小是处理块大小,而不是输出hash的大小
如,SHA-1和SHA-256 B和MD5的 B= 64
SHA-384和SHA-512的 B = 128
L 表示hash的大小 MD5的L=128、SHA-1的L=160。其他的不再一一介绍。
Opad 用0x5c重复B次
Ipad 用0x36重复B次
看到这里好晕呀,那么接下来一MD5作为摘要算法来介绍这个加密算法:
1.K:秘钥 它的长度根据摘要算法处理的数据块B的大小来确定的,这里是64位 若秘钥K的长度不足64位 则需要使用0来补位达到64位,太短的秘钥是不受欢迎的 因为太短了安全性就会降低;若秘钥的长度刚好等于64位 就不用处理了;若秘钥的长度大于64位,则需要先对秘钥做摘要算法计算把结果作为秘钥key。
2.Opad 为重复64次的0x5c 就是64个0x5c组成的串。
3.同理 Ipad 是64个0x36组成的串。
(这里有个疑问 若秘钥长度小于等于64 则秘钥处理后变成长度为64的秘钥 若秘钥长度大于64 则秘钥处理后就变成了长度位128的秘钥 他和ipad和opad是如何做与或运算呢?)
算法需要的材料已备好,开始加密了.
1.用处理好的秘钥和inpad做异或运算 生成S1。
2.将待加密的数据放到S1后面 做摘要算法 这里是MD5摘要 生成H。
3.用处理好的秘钥和Opad做异或运算 生成S2。
4.将第三步的H和S2拼接到一起 用MD5做摘要 生成最终的HMAC的密文。
java代码
package util; import javax.crypto.KeyGenerator; import javax.crypto.Mac; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; /** * @ClassName : MAC * @Description : java中提供了 HmacMD5、HmacSHA1、HmacSHA256、HmacSHA384和HmacSHA512四中算法支持 * @author : wangdx * @date : 2016-3-15 下午10:05:49 * */ public class MAC { public static byte[] initHmacMD5Key()throws Exception{ //初始化 KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); // 产生秘钥 SecretKey secretKey = keyGenerator.generateKey(); //获得秘钥 return secretKey.getEncoded(); } public static byte[] encodeHmacMD5(byte[] data,byte[] key)throws Exception{ //还原秘钥 SecretKey secretKey = new SecretKeySpec(key, "HmacMD5"); //实例化Mac Mac mac = Mac.getInstance(secretKey.getAlgorithm()); //初始化Mac mac.init(secretKey); //执行消息摘要 return mac.doFinal(data); } public static byte[] initHmacSHAKey()throws Exception{ //初始化 KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA1"); // 产生秘钥 SecretKey secretKey = keyGenerator.generateKey(); //获得秘钥 return secretKey.getEncoded(); } public static byte[] encodeHmacSHA(byte[] data,byte[] key)throws Exception{ //还原秘钥 SecretKey secretKey = new SecretKeySpec(key, "HmacSHA1"); //实例化Mac Mac mac = Mac.getInstance(secretKey.getAlgorithm()); //初始化Mac mac.init(secretKey); //执行消息摘要 return mac.doFinal(data); } public static byte[] initHmacSHA256Key()throws Exception{ //初始化 KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA256"); // 产生秘钥 SecretKey secretKey = keyGenerator.generateKey(); //获得秘钥 return secretKey.getEncoded(); } public static byte[] encodeHmacSHA256(byte[] data,byte[] key)throws Exception{ //还原秘钥 SecretKey secretKey = new SecretKeySpec(key, "HmacSHA256"); //实例化Mac Mac mac = Mac.getInstance(secretKey.getAlgorithm()); //初始化Mac mac.init(secretKey); //执行消息摘要 return mac.doFinal(data); } public static byte[] initHmacSHA384Key()throws Exception{ //初始化 KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA384"); // 产生秘钥 SecretKey secretKey = keyGenerator.generateKey(); //获得秘钥 return secretKey.getEncoded(); } public static byte[] encodeHmacSHA384(byte[] data,byte[] key)throws Exception{ //还原秘钥 SecretKey secretKey = new SecretKeySpec(key, "HmacSHA384"); //实例化Mac Mac mac = Mac.getInstance(secretKey.getAlgorithm()); //初始化Mac mac.init(secretKey); //执行消息摘要 return mac.doFinal(data); } public static byte[] initHmacSHA512Key()throws Exception{ //初始化 KeyGenerator KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacSHA512"); // 产生秘钥 SecretKey secretKey = keyGenerator.generateKey(); //获得秘钥 return secretKey.getEncoded(); } public static byte[] encodeHmacSHA512(byte[] data,byte[] key)throws Exception{ //还原秘钥 SecretKey secretKey = new SecretKeySpec(key, "HmacSHA512"); //实例化Mac Mac mac = Mac.getInstance(secretKey.getAlgorithm()); //初始化Mac mac.init(secretKey); //执行消息摘要 return mac.doFinal(data); } } package test; import static org.junit.Assert.*; import org.junit.Test; import util.MAC; public class MACTest { /** * @Title : testEncodeHmacMD5 * @Description : 测试HmacMD5 * @return : void 返回类型 * @throws */ @Test public final void testEncodeHmacMD5()throws Exception{ String str = "测试一"; //初始化秘钥 byte[] key = MAC.initHmacMD5Key(); //获得摘要信息 byte[] data1 = MAC.encodeHmacMD5(str.getBytes(), key); byte[] data2 = MAC.encodeHmacMD5(str.getBytes(), key); //校验 assertArrayEquals(data1, data2); } /** * @Title : testEncodeHmacSHA * @Description : 测试 HmacSHA * @return : void 返回类型 * @throws */ @Test public final void testEncodeHmacSHA()throws Exception{ String str = "测试二"; //初始化秘钥 byte[] key = MAC.initHmacSHAKey(); //获得摘要信息 byte[] data1 = MAC.encodeHmacSHA(str.getBytes(), key); byte[] data2 = MAC.encodeHmacSHA(str.getBytes(), key); //校验 assertArrayEquals(data1, data2); } @Test public final void testEncodeHmacSHA256()throws Exception{ String str = "测试二"; //初始化秘钥 byte[] key = MAC.initHmacSHA256Key(); //获得摘要信息 byte[] data1 = MAC.encodeHmacSHA256(str.getBytes(), key); byte[] data2 = MAC.encodeHmacSHA256(str.getBytes(), key); //校验 assertArrayEquals(data1, data2); } @Test public final void testEncodeHmacSHA384()throws Exception{ String str = "测试二"; //初始化秘钥 byte[] key = MAC.initHmacSHA384Key(); //获得摘要信息 byte[] data1 = MAC.encodeHmacSHA384(str.getBytes(), key); byte[] data2 = MAC.encodeHmacSHA384(str.getBytes(), key); //校验 assertArrayEquals(data1, data2); } @Test public final void testEncodeHmacSHA512()throws Exception{ String str = "测试二"; //初始化秘钥 byte[] key = MAC.initHmacSHA512Key(); //获得摘要信息 byte[] data1 = MAC.encodeHmacSHA512(str.getBytes(), key); byte[] data2 = MAC.encodeHmacSHA512(str.getBytes(), key); //校验 assertArrayEquals(data1, data2); } }
典型应用
HMAC的一个典型应用是用在“质疑/应答”(Challenge/Response)身份认证中。
认证流程
(1) 先由客户端向服务器发出一个验证请求。
(2) 服务器接到此请求后生成一个随机数并通过网络传输给客户端(此为质疑)。
(3) 客户端将收到的随机数提供给ePass,由ePass使用该随机数与存储在ePass中的密钥进行HMAC-MD5运算并得到一个结果作为认证证据传给服务器(此为响应)。
(4) 与此同时,服务器也使用该随机数与存储在服务器数据库中的该客户密钥进行HMAC-MD5运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户
相关文章推荐
- java IO流——字节流
- 35 个 Java 代码性能优化总结
- java4种内部类
- eclipse无法启动的各种解决方法
- Java实例化类详解
- 修改java.exe启动服务名称
- springMVC-springMVC入门实例
- Java数组初始化
- Java多线程(二)
- Java day07内部类到匿名内部类
- Spring MVC返回JSON的几种方法
- Java 图片服务器
- Java Selenium模拟某电商登录获取豆豆信息+JUnit单元测试
- JAVA中常见的锁
- Java单元测试初试
- LeetCode : Combination Sum II [java]
- Java并发编程:CopyOnWrite容器的实现
- Java 实现多线程的几种方式汇总
- Java String 字符串 比较 == equals
- 深入理解Java的接口和抽象类