MD5加盐加密工具类
在我们做项目时,涉及到用户密码,而正常来说数据库中不会直接存储明文的密码,都是加密之后的密码。
密码加密的方式有很多,比如:
① 3DES、AES、DES:使用对称加密算法,可以通过解密来还原出原始密码
② MD5、SHA1:使用单向HASH算法,无法通过计算还原出原始密码,但是可以建立彩虹表进行查表破解
简单的MD5解密方法需要用到这个网站(有兴趣的小伙伴可以自己试一试),免费MD5解密网站:https://md5.cn/
使用MD5可进行加盐加密,保证安全,下面给大家分享项目中用到的MD5加盐加密工具类。
- 将密码加密加盐
public static String getEncryptedPwd(String password)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
// 声明加密后的口令数组变量
byte[] pwd = null;
// 随机数生成器
SecureRandom random = new SecureRandom();
// 声明盐数组变量
byte[] salt = new byte[SALT_LENGTH];
// 将随机数放入盐变量中
random.nextBytes(salt);
// 声明消息摘要对象
MessageDigest md = null;
// 创建消息摘要
md = MessageDigest.getInstance("MD5");
// 将盐数据传入消息摘要对象
md.update(salt);
// 将口令的数据传给消息摘要对象
md.update(password.getBytes("UTF-8"));
// 获得消息摘要的字节数组
byte[] digest = md.digest();
// 因为要在口令的字节数组中存放盐,所以加上盐的字节长度
pwd = new byte[digest.length + SALT_LENGTH];
// 将盐的字节拷贝到生成的加密口令字节数组的前12个字节,以便在验证口令时取出盐
System.arraycopy(salt, 0, pwd, 0, SALT_LENGTH);
// 将消息摘要拷贝到加密口令字节数组从第13个字节开始的字节
System.arraycopy(digest, 0, pwd, SALT_LENGTH, digest.length);
// 将字节数组格式加密后的口令转化为16进制字符串格式的口令
return byteToHexString(pwd);
}
- 验证密码(登录时传入密码)
public static boolean validPassword(String password, String passwordInDb)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
// 将16进制字符串格式口令转换成字节数组
byte[] pwdInDb = hexStringToByte(passwordInDb);
// 声明盐变量
byte[] salt = new byte[SALT_LENGTH];
// 将盐从数据库中保存的口令字节数组中提取出来
System.arraycopy(pwdInDb, 0, salt, 0, SALT_LENGTH);
// 创建消息摘要对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 将盐数据传入消息摘要对象
md.update(salt);
// 将口令的数据传给消息摘要对象
md.update(password.getBytes());
// 生成输入口令的消息摘要
byte[] digest = md.digest();
// 声明一个保存数据库中口令消息摘要的变量
byte[] digestInDb = new byte[pwdInDb.length - SALT_LENGTH];
// 取得数据库中口令的消息摘要
System.arraycopy(pwdInDb, SALT_LENGTH, digestInDb, 0, digestInDb.length);
// 比较根据输入口令生成的消息摘要和数据库中消息摘要是否相同
if (Arrays.equals(digest, digestInDb)) {
// 口令正确返回口令匹配消息
return true;
} else {
// 口令不正确返回口令不匹配消息
return false;
}
}
- 完整工具类代码如下
package com.codingfuture.utils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
public class MD5SaltUtil {
private static final String HEX_NUMS_STR = "0123456789ABCDEF";
private static final Integer SALT_LENGTH = 12;
//将16进制字符转换为字节数组
public static byte[] hexStringToByte(String hex) {
int len = (hex.length() / 2);
byte[] result = new byte[len];
char[] hexChars = hex.toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (HEX_NUMS_STR.indexOf(hexChars[pos]) << 4 | HEX_NUMS_STR
.indexOf(hexChars[pos + 1]));
}
return result;
}
//将指定byte数组转换成16进制字符串
public static String byteToHexString(byte[] b) {
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < b.length; i++) {
String hex = Integer.toHexString(b[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
hexString.append(hex.toUpperCase());
}
return hexString.toString();
}
//验证口令是否合法
public static boolean validPassword(String password, String passwordInDb)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
// 将16进制字符串格式口令转换成字节数组
byte[] pwdInDb = hexStringToByte(passwordInDb);
// 声明盐变量
byte[] salt = new byte[SALT_LENGTH];
// 将盐从数据库中保存的口令字节数组中提取出来
System.arraycopy(pwdInDb, 0, salt, 0, SALT_LENGTH);
// 创建消息摘要对象
MessageDigest md = MessageDigest.getInstance("MD5");
// 将盐数据传入消息摘要对象
md.update(salt);
// 将口令的数据传给消息摘要对象
md.update(password.getBytes());
// 生成输入口令的消息摘要
byte[] digest = md.digest();
// 声明一个保存数据库中口令消息摘要的变量
byte[] digestInDb = new byte[pwdInDb.length - SALT_LENGTH];
// 取得数据库中口令的消息摘要
System.arraycopy(pwdInDb, SALT_LENGTH, digestInDb, 0, digestInDb.length);
// 比较根据输入口令生成的消息摘要和数据库中消息摘要是否相同
if (Arrays.equals(digest, digestInDb)) {
// 口令正确返回口令匹配消息
return true;
} else {
// 口令不正确返回口令不匹配消息
return false;
}
}
//获得加密后的口令
public static String getEncryptedPwd(String password)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
// 声明加密后的口令数组变量
byte[] pwd = null;
// 随机数生成器
SecureRandom random = new SecureRandom();
// 声明盐数组变量
byte[] salt = new byte[SALT_LENGTH];
// 将随机数放入盐变量中
random.nextBytes(salt);
// 声明消息摘要对象
MessageDigest md = null;
// 创建消息摘要
md = MessageDigest.getInstance("MD5");
// 将盐数据传入消息摘要对象
md.update(salt);
// 将口令的数据传给消息摘要对象
md.update(password.getBytes("UTF-8"));
// 获得消息摘要的字节数组
byte[] digest = md.digest();
// 因为要在口令的字节数组中存放盐,所以加上盐的字节长度
pwd = new byte[digest.length + SALT_LENGTH];
// 将盐的字节拷贝到生成的加密口令字节数组的前12个字节,以便在验证口令时取出盐
System.arraycopy(salt, 0, pwd, 0, SALT_LENGTH);
// 将消息摘要拷贝到加密口令字节数组从第13个字节开始的字节
System.arraycopy(digest, 0, pwd, SALT_LENGTH, digest.length);
// 将字节数组格式加密后的口令转化为16进制字符串格式的口令
return byteToHexString(pwd);
}
}