Java MD5信息摘要算法工具类
一、Java MD5算法
信息学中使用广泛的哈希算法,但严格意义上属于是信息摘要算法,是用来判定消息有没有被篡改的,或者说给信息生成一个身份证的,不属于加密算法。而且MD算法中,MD5安全性最高,就算加随机盐,还是会有破解的风险(最多是增加破解难度),攻击者可通过暴力破解或彩虹表攻击等方式,找到与原始数据相同的哈希值,从而破解数据。而且,MD5 算法本身就存在弱碰撞(Collision)问题,即输入多个不同的值会产生相同的MD5值,这是不安全的算法。
还记得刚工作时的公司项目是用两次MD5加密都被破解,而现在网上也还有很多项目实战教程采用 MD5 + Salt 的方式加密密码,导致公司有很多项目还在用MD5加密,能换就换咯吧。
简单项目用来做加密一般也没有人攻击,但确实MD5不被推荐用来加密密码,加密就用加密算法,推荐使用Spring Security 提供的KDF 算法,包含PBKDF2、Bcrypt、Scrypt2、Argon2(安全程度依次递增),对于绝大部分项目Bcrypt 综合性价比高,已足够系统安全性。
这里还是提供MD5算法代码,简单毕设项目可以食用。
二、MD5算法代码
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
/**
* @describe:
* @author: 容若
* @created: 2024-03-13 11:16
*/
public class MD5Util {
/** * byte[]字节数组 转换成 十六进制字符串 * * @param arr 要转换的byte[]字节数组 * * @return String 返回十六进制字符串 */
private static String hex(byte[] arr) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < arr.length; ++i) {
sb.append(Integer.toHexString((arr[i] & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
}
/** * MD5加密,并把结果由字节数组转换成十六进制字符串 * * @param str 要加密的内容 * * @return String 返回加密后的十六进制字符串 */
private static String md5Hex(String str) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(str.getBytes());
return hex(digest);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.toString());
return "";
}
}
/** * 生成含有随机盐的密码 * * @param password 要加密的密码 * * @return String 含有随机盐的密码 */
public static String getSaltMD5(String password) {
// 生成一个16位的随机数
Random random = new Random();
StringBuilder sBuilder = new StringBuilder(16);
sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
int len = sBuilder.length();
if (len < 16) {
for (int i = 0; i < 16 - len; i++) {
sBuilder.append("0");
}
}
// 生成最终的加密盐
String salt = sBuilder.toString();
password = md5Hex(password + salt);
char[] cs = new char[48];
for (int i = 0; i < 48; i += 3) {
cs[i] = password.charAt(i / 3 * 2);
char c = salt.charAt(i / 3);
cs[i + 1] = c;
cs[i + 2] = password.charAt(i / 3 * 2 + 1);
}
return String.valueOf(cs);
}
/** * 验证加盐后是否和原密码一致 * * @param password 原密码 * * @param password 加密之后的密码 * *@return boolean true表示和原密码一致 false表示和原密码不一致 */
public static boolean getSaltverifyMD5(String password, String md5str) {
char[] cs1 = new char[32];
char[] cs2 = new char[16];
for (int i = 0; i < 48; i += 3) {
cs1[i / 3 * 2] = md5str.charAt(i);
cs1[i / 3 * 2 + 1] = md5str.charAt(i + 2);
cs2[i / 3] = md5str.charAt(i + 1);
}
String Salt = new String(cs2);
return md5Hex(password + Salt).equals(String.valueOf(cs1));
}
public static void main(String[] args) {
// 原密码
String password = "dcxinP@ssw0rd_2024";
// 获取加盐后的MD5值
String ciphertext = MD5Util.getSaltMD5(password);
System.out.println("加盐后MD5:" + ciphertext);
// 验证密码
System.out.println("是否是同一字符串:" + MD5Utils.getSaltverifyMD5(password, ciphertext));
}
}
运行结果:
加盐后MD5:348465a9b36df70696e4ce65188b0ff6125710575ff34189
是否是同一字符串:true