看本文前,最好先看看之前的对于MD5算法和SHA算法的介绍。
本文目录
- 定义
- 常见应用场景
- 1、linux客户端:SecureCRT
- 2、Google身份验证器
- 3、银联pos机终端
- 原理
- java实现和使用
定义
MAC(Message Authentication Codes),是一种消息摘要算法,也叫消息认证码算法。
这种算法的核心是基于秘钥的散列函数。
可以理解为,MAC算法,是MD5算法和SHA算法的升级版,是在这两种算法的基础上,又加入了秘钥的概念,更加安全。
所以,有时候又叫MAC算法为HMAC算法(keyed-Hash Message Authentication Codes),即含有秘钥的散列算法。
常见的MAC算法有以下两大类:
MD系列:HmacMD2、HmacMD4、HmacMD5
SHA系列:HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384、HmacSHA512
大致用法:
如下图,发送端根据message和一个mac算法,生成mac秘钥
将mac秘钥和message同时发送
接收端收到message,用同样的mac算法,得到mac秘钥,
判断自己生成mac秘钥和接收到的mac秘钥是否一致,从而判断message是否一致
常见应用场景
mac算法的应用场景,相比MD和SHA系列,要更为复杂,高级一点。
1、linux客户端:SecureCRT
SecureCRT就用到了MAC算法
2、Google身份验证器
服务提供商为每个用户生成80位的密钥(然而RFC 4226 §4要求使用128位并建议使用160位密钥)。它以16位、26位或者32位base32的字符串亦或是二维码的方式提供出来。客户端使用此密钥生成HMAC-SHA1。
具体可看维基百科的介绍
3、银联pos机终端
中国银联直联POS终端规范下载链接 主要截图如下:
原理
根据RFC 2104,HMAC的数学公式为:
其中:
H为密码散列函数(如MD5或SHA-1)
K为密钥(secret key)
m是要认证的消息
K’是从原始密钥K导出的另一个秘密密钥(如果K短于散列函数的输入块大小,则向右填充(Padding)零;如果比该块大小更长,则对K进行散列)
|| 代表串接
⊕ 代表异或(XOR)
opad 是外部填充(0x5c5c5c…5c5c,一段十六进制常量)
ipad 是内部填充(0x363636…3636,一段十六进制常量)
java实现和使用
import org.apache.commons.codec.binary.Hex;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
public class HmacMD5Util {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
System.out.println(encodeString("123"));
}
public static String encodeString(String plainText) throws UnsupportedEncodingException {
return encodeBytes(plainText.getBytes("utf-8"));
}
public static String encodeBytes(byte[] bytes) {
try {
// // JDK的获取秘钥
// byte[] key = getKey();
// 指定秘钥
byte[] key = Hex.decodeHex(new char[]{'a', 'b', 'c', 'd'});
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "HmacMD5");
Mac mac = Mac.getInstance("HmacMD5");
mac.init(secretKeySpec);
byte[] b = mac.doFinal(bytes);
// return Hex.encodeHexString(b);
int i;
StringBuffer buf = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0) {
i += 256;
}
if (i < 16) {
buf.append("0");
}
buf.append(Integer.toHexString(i));
}
return buf.toString();
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public static byte[] getKey() throws NoSuchAlgorithmException {
KeyGenerator hmacMD5 = KeyGenerator.getInstance("HmacMD5");
SecretKey secretKey = hmacMD5.generateKey();
String algorithm = secretKey.getAlgorithm();// algorithm=HmacMD5
byte[] encoded = secretKey.getEncoded();
return encoded;
}
}
结果:
4b1dd5bb09ae59a17a65168da372c90e