业务需要到记录一下,直接上代码
import lombok.extern.slf4j.Slf4j;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Random;
/**
* @author :smallkinghjm
* @description:因为需要和django的的系统兼容,这里模拟django的check_password()方法实现对用户密码的加密及验证,只保证验证成功的版本
* jdk:1.8
* 加密算法:pbkdf2_sha256
* @date :2022/3/4 13:19
*/
@Slf4j
public class CryptoUtil {
private static Integer DEFAULT_ITERATIONS = 20000;//默认迭代次数
public static String algorithm = "pbkdf2_sha256";
private static String getEncodedHash(String password, String salt, int iterations) {
// 仅返回整个编码密码的最后一部分
SecretKeyFactory keyFactory = null;
try {
keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
} catch (NoSuchAlgorithmException e) {
log.info("无法检索PBKDF2WithHmacSHA256算法!!!");
}
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt.getBytes(Charset.forName("UTF-8")), iterations, 256);
SecretKey secret = null;
try {
secret = keyFactory.generateSecret(keySpec);
} catch (InvalidKeySpecException e) {
log.info("无法生成密钥");
e.printStackTrace();
}
byte[] rawHash = secret.getEncoded();
byte[] hashBase64 = Base64.getEncoder().encode(rawHash);
return new String(hashBase64);
}
/**
* 加盐
* @return
*/
private static String getSalt(){
int length = 12;
Random rand = new Random();
char[] rs = new char[length];
for(int i = 0; i < length; i++){
int t = rand.nextInt(3);
if (t == 0) {
rs[i] = (char)(rand.nextInt(10)+48);
} else if (t == 1) {
rs[i] = (char)(rand.nextInt(26)+65);
} else {
rs[i] = (char)(rand.nextInt(26)+97);
}
}
return new String(rs);
}
public static String encode(String password) {
return encode(password, getSalt());
}
private static String encode(String password,int iterations) {
return encode(password, getSalt(),iterations);
}
private static String encode(String password, String salt) {
return encode(password, salt, DEFAULT_ITERATIONS);
}
/**
*
* @param password
* @param salt
* @param iterations
* @return
*/
private static String encode(String password, String salt, int iterations) {
// 返回哈希密码,以及算法、迭代次数和salt
String hash = getEncodedHash(password, salt, iterations);
return String.format("%s$%d$%s$%s", algorithm, iterations, salt, hash);
}
/**
* 校验密码
* @param password
* @param hashedPassword
* @return
*/
public static boolean checkPassword(String password, String hashedPassword) {
/*
<algorithm>$<iterations>$<salt>$<hash>
以美元字符分分隔并由哈希算法、算法迭代次数(工作因数)、随机的salt、以及生成的密码哈希值组成
*/
String[] parts = hashedPassword.split("\\$");
if (parts.length != 4) {
//格式错误
return false;
}
Integer iterations = Integer.parseInt(parts[1]);
String salt = parts[2];
String hash = encode(password, salt, iterations);
return hash.equals(hashedPassword);
}
public static void main(String[] args) {
String encode = encode("Admin@2022");
System.out.println("后端加密:"+encode);
boolean check = checkPassword("Admin@2022", "pbkdf2_sha256$20000$T7314mPWi61g$pfswjCjI+geqU4bcTmhYe4mHp116eWuVxl35Si42Plk=");
System.out.println("密码校验结果:"+check);
}
}
参考:
java实现Django的PBKDF2PasswordHasher加密算法