您的位置:首页 > 编程语言 > Java开发

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代码

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运算,如果服务器的运算结果与客户端传回的响应结果相同,则认为客户端是一个合法用户
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: