MD5加密工具类
MD5加密工具类:
/**
* @Author
* @ClassName MD5Utils
* @Description MD5加密工具
* @Date 2021/3/15 17:52
* @Version 1.0
*/
public class MD5Utils {
private static final Logger logger = LoggerFactory.getLogger(MD5Utils.class);
/**
* Md5加密
* @param message 加密信息
* @return 返回 32 位的 字母 + 数字
*/
public static String MD5(String message) {
MessageDigest md5 = null;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
return "check jdk";
} catch (Exception e) {
e.printStackTrace();
return "";
}
byte[] byteArray = new byte[0];
try {
byteArray = message.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage());
}
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
/**
* MD5 加密支持传入加密后的位数、字母是否大小写
* @param pwd 需要加密的字符串
* @param isUpper 字母大小写(false为默认小写,true为大写)
* @param bit 加密的位数(16, 32, 64)
* @return
*/
public static String MD5(String pwd, boolean isUpper, Integer bit) {
String md5 = new String();
try {
// 创建加密对象
MessageDigest md = MessageDigest.getInstance("md5");
if (bit == 64) {
String bsB64 = Base64.encodeBase64String(md.digest(pwd.getBytes("utf-8")));
md5 = bsB64;
} else {
// 计算MD5函数
md.update(pwd.getBytes());
byte b[] = md.digest();
int i;
StringBuffer sb = new StringBuffer("");
for (int offset = 0; offset < b.length; offset++) {
i = b[offset];
if (i < 0)
i += 256;
if (i < 16)
sb.append("0");
sb.append(Integer.toHexString(i));
}
md5 = sb.toString();
if(bit == 16) {
//截取32位md5为16位
String md16 = md5.substring(8, 24);
md5 = md16;
if (isUpper)
md5 = md5.toUpperCase();
return md5;
}
}
//转换成大写
if (isUpper)
md5 = md5.toUpperCase();
} catch (Exception e) {
logger.error("md5加密抛出异常");
}
return md5;
}
/**
* 加盐MD5
* MD5加密,是属于不可逆的。我们知道正常使用MD5加密技术,
* 同一字符,加密后的16进制数是不变的,自从出现彩虹表,对于公司内部员工来说,
* 可以反查数据,获取不可能的权限,所以出现了salt算法。
* 因此我们做了一个非常简单的加盐算法,每次保存密码到数据库时,都生成一个随机16位数字,将这16位数字和密码相加再求MD5摘要,
* 然后在摘要中再将这16位数字按规则掺入形成一个48位的字符串。
* 在验证密码时再从48位字符串中按规则提取16位数字,和用户输入的密码相加再MD5。
* 按照这种方法形成的结果肯定是不可直接反查的,且同一个密码每次保存时形成的摘要也都是不同的。
*/
public static String generate(String password) {
Random r = new Random();
StringBuilder sb = new StringBuilder(16);
sb.append(r.nextInt(99999999)).append(r.nextInt(99999999));
int len = sb.length();
if (len < 16) {
for (int i = 0; i < 16 - len; i++) {
sb.append("0");
}
}
String salt = sb.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 new String(cs);
}
/**
* 校验加盐后 是否和原文一致
* @author
* @param password 明文密码
* @param md5 加密后的密文
* @return
*/
public static boolean verifyPasswordHasSalt(String password, String md5) {
char[] cs1 = new char[32];
char[] cs2 = new char[16];
for (int i = 0; i < 48; i += 3) {
cs1[i / 3 * 2] = md5.charAt(i);
cs1[i / 3 * 2 + 1] = md5.charAt(i + 2);
cs2[i / 3] = md5.charAt(i + 1);
}
String salt = new String(cs2);
return md5Hex(password + salt).equals(new String(cs1));
}
/**
* 获取十六进制字符串形式的MD5摘要
*/
private static String md5Hex(String src) {
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] bs = md5.digest(src.getBytes());
return new String(new Hex().encode(bs));
} catch (Exception e) {
return null;
}
}
}