MD5
全称是Message-Digest Algorithm 5(信息-摘要算法5),理论上是一种单向的哈希散列,特性:
输入任意长度的信息,经过处理,输出为128位的大整数(数字指纹)(32位16进制数); 不同的输入一般得到不同的结果(唯一性);
根据128位的输出结果不可能反推出输入的信息(不可逆); 强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
在实现MD5工具类时,需要借助一个类MessageDigest产生哈希映射值,先对该类进行简要介绍。
MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,输出固定长度的哈希值。
MessageDigest 对象开始被初始化。该对象通过使用 update 方法处理数据。任何时候都可以调用 reset 方法重置摘要。一旦所有需要更新的数据都已经被更新了,应该调用 digest 方法之一完成哈希计算。
对于给定数量的更新数据,digest 方法只能被调用一次。digest 被调用后,MessageDigest 对象被重新设置成其初始状态。
1、public static MessageDigest getInstance(String algorithm)
throws NoSuchAlgorithmException
返回实现指定摘要算法的 MessageDigest 对象。
algorithm - 所请求算法的名称
2、public static MessageDigest getInstance(String algorithm,String provider)throwsNoSuchAlgorithmException,NoSuchProviderException
返回实现指定摘要算法的 MessageDigest 对象。
algorithm - 所请求算法的名称
provider - 提供者的名称。
3、public void update(byte[] input)
使用指定的 byte 数组更新摘要。
4、public byte[] digest()
通过执行诸如填充之类的最终操作完成哈希计算。在调用此方法之后,摘要被重置。
5、public static boolean isEqual(byte[] digesta,
byte[] digestb)
比较两个摘要的相等性。做简单的字节比较。
3.1、创建 MessageDigest 对象
计算信息摘(即散列码)要做的第一步是创建 MessageDigest对象 实例。像所有的引擎类一样,获取某类报文摘要算法(即散列算法,比如MD5)的 MessageDigest 对象的途径是调用 MessageDigest 类中的 getInstance 静态 factory 方法:
public static MessageDigest getInstance(String algorithm)
注意:算法名不区分大小写。例如,以下所有调用都是相等的:
MessageDigest.getInstance("SHA");
MessageDigest.getInstance("sha");
MessageDigest.getInstance("sHa");
调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:
public static MessageDigest getInstance(String algorithm, String provider);
调用 getInstance 将返回已初始化过的MessageDigest对象。因此,它不需要进一步的初始化。
3.2、向MessageDigest传送要计算的数据
计算数据的摘要的第二步是向已初始化的MessageDigest对象提供传送要计算的数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:
public void update(byte input);
public void update(byte[] input);
public void update(byte[] input, int offset, int len);
3.3、计算摘要
通过调用 update 方法向MessageDigest对象提传送要计算的数据后,你就可以调用以下某个 digest(摘要)方法来计算摘要(即生成散列码):
public byte[] digest();
public byte[] digest(byte[] input);
public int digest(byte[] buf, int offset, int len);
MD5破解:是使用穷举法来进行破解。
如:我们计算出键盘上所有字符的组合的md5,将加密前后的字符串分别存入数据库中;然后拿你的md5加密后的字符串进行查询得出加密前的字符串。
*预防措施
本工具类基于第二种方式提供的加密策略
配置文件信息:
password.salt = Ambitonsdafaqj23ou89ZXcj@#$@#$#@KJdjklj;D../dSF.,`
主要作用在于读取配置文件中提供的password.salt的信息内容,主要是避免硬编码的形式,便于后续维护所考虑,如果单纯为了测试,可以直接写到代码中,根据实际情况进行选择。
/***
***/
public class PropertiesUtil {
private static Properties props;
// 静态初始化
static {
String fileName = "配置文件文件名.properties";
// 实例化一个对象后,装载内容
props = new Properties();
InputStream inputStream = PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName);
try {
// 装载内容
props.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getProperty(String key,String defaultValue){
String value = props.getProperty(key.trim());
if(StringUtils.isBlank(value)){
value = defaultValue;
}
return value.trim();
}
private static String getProperty(String key) {
String value = props.getProperty(key.trim());
if (StringUtils.isBlank(value)) {
return null;
}
return value.trim();
}
}
/**
* @description MD5工具类
* @create: 2020-07-22 17:58
**/
public class MD5Util {
private static final String hexDigits[] = {
"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/**
* 返回加密后的信息内容string
* @param origin
* @return
*/
public static String MD5EncodeUtf8(String origin) {
// 获取后缀信息
origin = origin + PropertiesUtil.getProperty("password.salt", "");
return MD5Encode(origin, "utf-8");
}
private static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
if(charsetname == null || "".equals(charsetname)){
// 默认编码信息格式处理 默认格式为utf-8编码处理
resultString = byteArrayToHexString(md.digest(origin.getBytes()));
}else{
// 主要为了应该不同信息的编码
resultString = byteArrayToHexString(md.digest(origin.getBytes(charsetname)));
}
}catch (Exception exception){
throw new RuntimeException("无法获取加密算法");
}
// 全部转成大写
return resultString.toUpperCase();
}
private static String byteArrayToHexString(byte[] digest) {
StringBuilder resultString = new StringBuilder();
for( int i = 0 ; i <digest.length; i ++ ) {
resultString.append(byteToHexString(digest[i]));
}
return resultString.toString();
}
/***
* 对单个字符进行加密处理
* @param b
* @return
*/
private static String byteToHexString(byte b) {
int n = b;
// 注意:此时进行映射时,数据会转成byte形式 byte数据范围在 -128 - 127
// 由于对16取模,加256后变成整数,并不影响数据
if ( n < 0) {
n += 256;
}
// 获取字符下标信息
int d1 = n / 16;
int d2 = n % 16;
//返回信息
return hexDigits[d1] + hexDigits[d2];
}
}