概述
消息摘要算法包括
MD(Message Digest,消息摘要算法)、
SHA(Secure Hash Algorithm,安全散列算法)、
MAC(Message AuthenticationCode,消息认证码算法)
共3大系列,常用于验证数据的完整性,是数字签名算法的核心算法。
MD5和SHA1分别是MD、SHA算法系列中最有代表性的算法。
如今,MD5已被发现有许多漏洞,从而不再安全。SHA算法比MD算法的摘要长度更长,也更加安全。
算法实现
MD5、SHA的范例
JDK中使用MD5和SHA这两种消息摘要的方式基本一致,步骤如下:
(1) 初始化MessageDigest对象
(2) 更新要计算的内容
(3) 生成摘要
package com.zoo.lion.security;
import org.apache.commons.codec.binary.Hex;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @Author: xf
* @Date: 2019/6/3 13:28
* @Version 1.0
*/
public class Md5Coder {
public enum Algorithm {
md5("md5"), SHA("SHA"), sha256("SHA-256"), sha384("SHA-384"), sha512("SHA-512");
private String algorithm;
Algorithm(String algorithm) {
this.algorithm = algorithm;
}
public String getAlgorithm() {
return algorithm;
}
}
public static void main(String[] args) {
String md5 = md5("123456");
System.out.println("MD5摘要: " + md5);
String sha = sha("123456");
System.out.println("sha摘要: " + sha);
}
public static String md5(String msg) {
try {
//编码
byte[] encrypt = encrypt(msg, Algorithm.md5.getAlgorithm());
// //(自己实现转换)
// //字节数组转换为字符
// char[] str = byteArrayToHexString(encrypt);
// return new String(str);// 换后的结果转换为字符串
return Hex.encodeHexString(encrypt);//利用org.apache.commons包转换
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
public static String sha(String msg) {
try {
//编码
byte[] encrypt = encrypt(msg, Algorithm.sha512.getAlgorithm());
String sha = Hex.encodeHexString(encrypt);
return sha;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
/**
* byte[]转化为16进制(有多种方法)
*
* @param data 要转换的byte
* @return 16进制格式
*/
private static char[] byteArrayToHexString(byte[] data) {
// 用来将字节转换成16进制表示的字符
char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
// 用字节表示就是 16 个字节 进制需要 32 个字符
char[] str = new char[16 * 2];// 每个字节用 16 进制表示的话,使用两个字符, 所以表示成 16
// 表示转换结果中对应的字符位置
int index = 0;
// // 遍历字节数组,通过位运算(位运算效率高),转换成字符放到字符数组中去 ,从第一个字节开始,对 MD5 的每一个字节转换成 16进制
for (byte b : data) {
// 进制字符的转换
str[index++] = hexDigits[b >>> 4 & 0xf];// 取字节中高 4 位的数字转换,// >>>
// 为逻辑右移,将符号位一起右移
str[index++] = hexDigits[b & 0xf];// 取字节中低 4 位的数字转换
}
return str;
}
//编码
private static byte[] encrypt(String msg, String algorithm) throws NoSuchAlgorithmException {
// 拿到一个MD5转换器(如果想要SHA1参数换成”SHA1”)
MessageDigest md5Digest = MessageDigest.getInstance(algorithm);
// 更新要计算的内容
md5Digest.update(msg.getBytes());
// 完成哈希计算,得到摘要,结果是一个 128 位的长整数
return md5Digest.digest();
}
}
Hmac的范例
package com.zoo.lion.security;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
/**
* @Author: xf
* @Date: 2019/6/3 15:08
* @Version 1.0
*/
public class HmacCoder {
/**
* JDK支持HmacMD5, HmacSHA1,HmacSHA256, HmacSHA384, HmacSHA512
*/
public enum HmacTypeEn {
HmacMD5, HmacSHA1, HmacSHA256, HmacSHA384, HmacSHA512;
}
public static byte[] encode(byte[] plaintext, byte[] secretKey, HmacTypeEn type) throws NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec keySpec = new SecretKeySpec(secretKey, type.name());
Mac mac = Mac.getInstance(keySpec.getAlgorithm());
mac.init(keySpec);
return mac.doFinal(plaintext);
}
public static void main(String[] args) throws Exception {
String msg = "123456";
String secretKey = "123456";
byte[] digest = HmacCoder.encode(msg.getBytes(), secretKey.getBytes(StandardCharsets.UTF_8), HmacTypeEn.HmacSHA1);
System.out.println("原文: " + msg);
System.out.println("摘要: " + Hex.encodeHexString(digest));
}
}
(完)