Java方式通实现用户密码加密
消息摘要算法的特征是加密过程不需要秘钥
,并且加密的数据无法被解密
。任何消息经过散列函数
处理后,都会获得唯一的散列值,这一过程称为“消息摘要”。
消息摘要算法最著名的是MD5算法和SHA-1算法及其变体
。
MD5算法长度为128位(16字节),SHA-1算法长度为160位(20字节),SHA-256算法长度为256位(64字节)。
消息摘要函数是单向函数,只能正向求得密文,无法反向求明文信息
。
单向加密,即加密之后不能解密
,一般用于数据验证。
java没有实现MD5解密操作
,但是有些网站可以完成解密
MD5加密的三种方式:
说明:都是返回长度为32位的16进制字符串(小写)。
MD5 是哈希散列算法(也称摘要算法),对于 MD5 而言,有两个特性是很重要的,
明文数据经过散列以后的值是定长的;
是任意一段明文数据,经过散列以后,其结果必须永远是不变的。
此方式需要 安装 commons-codec 依赖
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
<version>1.15version>
dependency>
import org.apache.commons.codec.digest.DigestUtils;
/**
* MD5加密方式一:借助apache工具类DigesUtils实现(推荐使用)
*
* 此方式需要 安装 commons-codec 依赖
* @param str 待加密字符串
* @return 16进制加密字符串(32位MD5码)
*/
public static String encryptToMD5(String str){
//MD5 加密,返回 32 位
return DigestUtils.md5Hex(str);
}
org.apache.commons.codec.digest.DigestUtils 类:
/**
* MD5加密方式二:使用JDK自带的java.security.MessageDigest下的MessageDigest类
* @param str 待加密字符串
* @return 16进制加密字符串(32位MD5码)
*/
public static String encrypt2ToMD5(String str) throws NoSuchAlgorithmException {
//MD5 加密(使用MD5算法)
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
//为了使用方便,将输出值转换为十六进制保存
return bytesToHexString(md5Bytes);
}
/**
* 将输出值转换为十六进制保存
* @param bytes
* @return
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder();
if (bytes == null || bytes.length <= 0) {
return null;
}
for (byte aByte : bytes) {
int v = aByte & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
安装spring 核心包 依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.7.2version>
dependency>
org.springframework.util.DigestUtils.md5DigestAsHex
/**
* MD5加密方式三:Spring核心包(Spring Boot 自带MD5加密)
* @param str 待加密字符串
* @return 16进制加密字符串(32位MD5码 小写)
*/
public static String encrypt3ToMD5(String str){
return org.springframework.util.DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8));
}
MD5工具类 完整代码:
package utils;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* ND5加密
* @author qzz
*/
public class MD5Util {
/**
* MD5加密方式一:借助apache工具类DigesUtils实现(推荐使用)
*
* 此方式需要 安装 commons-codec 依赖
* @param str 待加密字符串
* @return 16进制加密字符串(32位MD5码)
*/
public static String encryptToMD5(String str){
//MD5 加密,返回 32 位
return DigestUtils.md5Hex(str);
}
/**
* MD5加密方式二:使用JDK自带的java.security.MessageDigest下的MessageDigest类
* @param str 待加密字符串
* @return 16进制加密字符串(32位MD5码)
*/
public static String encrypt2ToMD5(String str) throws NoSuchAlgorithmException {
//MD5 加密(使用MD5算法)
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
//为了使用方便,将输出值转换为十六进制保存
return bytesToHexString(md5Bytes);
}
/**
* MD5加密方式三:Spring核心包(Spring Boot 自带MD5加密)
* @param str 待加密字符串
* @return 16进制加密字符串(32位MD5码 小写)
*/
public static String encrypt3ToMD5(String str){
return org.springframework.util.DigestUtils.md5DigestAsHex(str.getBytes(StandardCharsets.UTF_8));
}
/**
* 将输出值转换为十六进制保存
* @param bytes
* @return
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder();
if (bytes == null || bytes.length <= 0) {
return null;
}
for (byte aByte : bytes) {
int v = aByte & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public static void main(String[] args) throws NoSuchAlgorithmException {
String str="123456";
System.out.println("MD5待加密字符串:"+str);
String md5Str=MD5Util.encryptToMD5(str);
System.out.println("方式一:MD5加密结果:"+md5Str);
String md5Str2=MD5Util.encrypt2ToMD5(str);
System.out.println("方式二:MD5加密结果:"+md5Str2);
String md5Str3=MD5Util.encrypt3ToMD5(str);
System.out.println("方式三:MD5加密结果:"+md5Str3);
}
}
执行结果:
"D:\Program Files\Java\jdk1.8.0_40\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=62529:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_40\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\rt.jar;F:\study-project\password-validate\target\classes;D:\mvnrepository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-web\2.7.2\spring-boot-starter-web-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter\2.7.2\spring-boot-starter-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot\2.7.2\spring-boot-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-autoconfigure\2.7.2\spring-boot-autoconfigure-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-logging\2.7.2\spring-boot-starter-logging-2.7.2.jar;D:\mvnrepository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\mvnrepository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\mvnrepository\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;D:\mvnrepository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\mvnrepository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\mvnrepository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\mvnrepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\mvnrepository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\mvnrepository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\mvnrepository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-json\2.7.2\spring-boot-starter-json-2.7.2.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-databind\2.13.3\jackson-databind-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-annotations\2.13.3\jackson-annotations-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-core\2.13.3\jackson-core-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.3\jackson-datatype-jdk8-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.3\jackson-datatype-jsr310-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.3\jackson-module-parameter-names-2.13.3.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-tomcat\2.7.2\spring-boot-starter-tomcat-2.7.2.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.65\tomcat-embed-core-9.0.65.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.65\tomcat-embed-el-9.0.65.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.65\tomcat-embed-websocket-9.0.65.jar;D:\mvnrepository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\mvnrepository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\mvnrepository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\mvnrepository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\mvnrepository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\mvnrepository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar" utils.MD5Util
MD5待加密字符串:123456
方式一:MD5加密结果:e10adc3949ba59abbe56e057f20f883e
方式二:MD5加密结果:e10adc3949ba59abbe56e057f20f883e
方式三:MD5加密结果:e10adc3949ba59abbe56e057f20f883e
Process finished with exit code 0
MD5 曾一度被认为是非常安全的。但是 MD5 也不会完全不重复,从概率来说 16 的 32 次方遍历后至少出现两个相同的 MD5 值。
以 Google 公司为例,Google 公司明确指出不建议再使用 MD5 算法,而使用 SHA256 算法替代
。
SHA-256 算法单向 Hash
函数是密码学和信息安全领域中的一个非常重要的基本算法,它是把任意长的消息转化为较短的、固定长度的消息摘要的算法
。SHA-256 算法是 SHA
算法族中的一员,由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布;是美国的政府标准。它的前辈还有 SHA-1。
随着密码学(破解)的发展,美国政府计划从 2010 年起不再使用 SHA-1,全面推广使用 SHA-256 和 SHA-512 等加密算法
。
对于任意长度的消息,SHA256 都会产生一个 256bit 长的哈希值,称作消息摘要
。这个摘要相当于是个长度为 32 个字节的数组,通常用一个长度为 64 的十六进制字符串来表示。
SHA256 加密实现方式:
import org.apache.commons.codec.digest.DigestUtils;
/**
* 加密方式一:借助apache工具类DigesUtils实现(推荐使用)
*
* 此方式需要 安装 commons-codec 依赖
* @param str 待加密字符串
* @return 16进制加密字符串(64位)
*/
public static String encryptToSHA256(String str){
//SHA-256 加密,返回 64 位
return DigestUtils.sha256Hex(str.getBytes(StandardCharsets.UTF_8));
}
/**
* 加密方式二:使用JDK自带的java.security.MessageDigest下的MessageDigest类
*
* 此方式需要 安装 commons-codec 依赖
* @param str 待加密字符串
* @return 16进制加密字符串(64位)
*/
public static String encrypt2ToSHA256(String str) throws NoSuchAlgorithmException {
//SHA-256 加密,返回 64 位
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] md5Bytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
//为了使用方便,将输出值转换为十六进制保存
return bytesToHexString(md5Bytes);
}
/**
* 将输出值转换为十六进制保存
* @param bytes
* @return
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder();
if (bytes == null || bytes.length <= 0) {
return null;
}
for (byte aByte : bytes) {
int v = aByte & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
SHA256加密工具类完整代码:
package utils;
import org.apache.commons.codec.digest.DigestUtils;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* SHA256加密
* @author qzz
*/
public class SHAUtil {
/**
* 加密方式一:借助apache工具类DigesUtils实现(推荐使用)
*
* 此方式需要 安装 commons-codec 依赖
* @param str 待加密字符串
* @return 16进制加密字符串(64位)
*/
public static String encryptToSHA256(String str){
//SHA-256 加密,返回 64 位
return DigestUtils.sha256Hex(str.getBytes(StandardCharsets.UTF_8));
}
/**
* 加密方式二:使用JDK自带的java.security.MessageDigest下的MessageDigest类
*
* 此方式需要 安装 commons-codec 依赖
* @param str 待加密字符串
* @return 16进制加密字符串(64位)
*/
public static String encrypt2ToSHA256(String str) throws NoSuchAlgorithmException {
//SHA-256 加密,返回 64 位
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] md5Bytes = md.digest(str.getBytes(StandardCharsets.UTF_8));
//为了使用方便,将输出值转换为十六进制保存
return bytesToHexString(md5Bytes);
}
/**
* 将输出值转换为十六进制保存
* @param bytes
* @return
*/
public static String bytesToHexString(byte[] bytes) {
StringBuilder stringBuilder = new StringBuilder();
if (bytes == null || bytes.length <= 0) {
return null;
}
for (byte aByte : bytes) {
int v = aByte & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
public static void main(String[] args) throws NoSuchAlgorithmException {
String str="123456";
System.out.println("SHA-256待加密字符串:"+str);
String sha256Str=SHAUtil.encryptToSHA256(str);
System.out.println("方式一:SHA-256加密结果:"+sha256Str);
String sha256Str2=SHAUtil.encrypt2ToSHA256(str);
System.out.println("方式二:SHA-256加密结果:"+sha256Str2);
}
}
java没有实现SHA-256解密操作
,但是有些网站可以完成解密
在线网址:
http://www.ttmd5.com/hash.php?type=9
注意:算法缺陷
使用MD5、SHA1等单向HASH算法保护密码,使用这些算法后,无法通过计算还原出原始密码,而且实现比较简单,因此很多互联网公司都采用这种方式保存用户密码,曾经这种方式也是比较安全的方式,但随着彩虹表
技术的兴起,可以建立彩虹表进行查表破解
,目前MD5算法和SHA-256算法已经很不安全了。
彩虹表是一个用于散列函数逆运算的预先计算好的表,该表有明文和一一对应的密文,所以能破解上面的算法。
package utils;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* base64加解码
*
* Java8 之后,JDK 工具包中提供了 Base64 特性,可以直接使用来完成编码和解码操作。
* @author qzz
*/
public class Base64Utils {
/**
* base64 编码
* @param text
* @return
*/
public static String encode(String text){
return new String(Base64.getEncoder().encode(text.getBytes(StandardCharsets.UTF_8)));
}
/**
* base64 解码
* @param encodedText
* @return
*/
public static String decode(String encodedText){
return new String(Base64.getDecoder().decode(encodedText.getBytes(StandardCharsets.UTF_8)));
}
public static void main(String[] args) {
String str="123456";
//编码
String encodedText=Base64Utils.encode(str);
System.out.println("编码后的字符串为:"+encodedText);
//解码
String text=Base64Utils.decode(encodedText);
System.out.println("解码后的字符串为:"+text);
}
}
执行结果:
"D:\Program Files\Java\jdk1.8.0_40\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=59517:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_40\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\rt.jar;F:\study-project\password-validate\target\classes" utils.Base64Utils
编码后的字符串为:MTIzNDU2
解码后的字符串为:123456
Process finished with exit code 0
注意:
使用 UTF-8 指定编码和解码格式,保证操作过程中不会出现中文乱码问题,如果不指定编码格式 Base64 会使用环境默认编码格式。
windows 下默认为 GBK 编码,而 Linux 下默认为 utf-8 编码,因此在编码和解码时指定统一的编码格式是良好的编程习惯。
package utils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;
/**
* 图片的Base64加解码
* @author qzz
*/
public class Base64ImageUtil {
/**
* 远程服务器图片转Base64字符串
* @param imageUrl
* @return
*/
public static String getImageBase64Str(String imageUrl){
//将图片文件转化为字节数组字符串,并进行Base64编码处理
byte[] data=null;
InputStream in=null;
ByteArrayOutputStream out=null;
//1.读取图片字节数组
try {
URL url = new URL(imageUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
in = connection.getInputStream();
out = new ByteArrayOutputStream();
data=new byte[1024];
int len = 0;
while((len = in.read(data))!=-1){
out.write(data,0,len);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
//2.对字节数组进行Base64编码
String base64Image = new String(Base64.getEncoder().encode(out.toByteArray()));
//如果需要将得到的 base64 字符串展示在 html 的 img 标签中,需要在字符串中添加 data:image/jpg;base64, 前缀
return base64Image;
}
/**
* Base64字符串转图片
* @param base64Image Base64字符串
* @param imagePath 转换完之后的图片存储地址
* @return
*/
public static void getImageUrlFormBase64(String base64Image,String imagePath){
if(base64Image==null){
return;
}
OutputStream out=null;
try {
byte[] data=Base64.getDecoder().decode(base64Image);
for(int i=0;i<data.length;i++){
if(data[i]<0){
data[i]+=256;
}
}
out=new FileOutputStream(imagePath);
out.write(data);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if(out!=null){
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//图片编码
String base64Image=Base64ImageUtil.getImageBase64Str("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
System.out.println("图片url转Base64字符串:"+base64Image);
//图片解码
Base64ImageUtil.getImageUrlFormBase64(base64Image,"F:\\image\\b1.png");
}
}
执行结果:
"D:\Program Files\Java\jdk1.8.0_40\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=61033:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_40\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\rt.jar;F:\study-project\password-validate\target\classes" utils.Base64ImageUtil
图片url转Base64字符串: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Ukk3/Mu1H72ejW7sb7GI9dOPhi+14IT/or+LPd6ixZ9f3xj77DM9ZgyQoeGWBjrYIObNu2HTO0vn0srbcygWx8l0bCLVjaqILRWBvINEkf3+lApKJtPph6r9VrvppOik9ead2l+6UXbSj3mHh3vXjwqHm51yoaT3qHjbgkF/JvmkKqt86NAY/+QTU+9dSKU7E+kzZ7aM6FLUu+nyehU5dwnCdGXCEq0MWrfEWYh+kevpR7mBS0ILDrdTYny3JKQOxSt3sLjYI9PIkMKVISoTQ2UmDaF4LsNI7nBSMIEcvAnkIB9GEwSz/zDD2T+ZR/rBhhXVKZ9k7SDc7JfP4hTjzA5dTtEhFAoJLvF24ri55sZbN5h91XqLT75AlZmu33f1Tbcv2l/OlpKSiqgSPkEvD+16ylW+y8c9H48Mhz/LxLWzfdiwYd2RPRNVRYyiM9ir11bu9TRWd0Q+0SufC3J553DkQqOhDrlHYOrMliNicfU6wcWldPMuTX8NuUrPZE10fV5B3cTveFT1PV7m/2DNK6MsRz6smy984rPgeHJfptDlfxY5JrPImTqK6pR2Z5VuMNrqgr9yLt/f1FC5LP0cUQIIgIBeAnA49JKCHAhkgMCcOW2l7T09l5EjMJ+Km21LTwH1mlGvw3pyZJqoB4OcDGk1K/WtzOTkSc0JYZ+2TKPeEG1p5CSyRYvJMJHqWU5/LW9Uv/epg+Y5r0968P3l1aaG0SwbAQUgAAJJCcDhSIoHiSCQPQKzZu0Y0hHvOpFuykdTb8FEuqFW0VDbcOqZ8NOJK1Gk6Dg5ED3UjdxNVu7gQuygCcVtNN+nhZ70m5kimj1e6dM1K6pasleL5CUfNXdzeaQ7Po4JtVYwqZZztZrqWkFDMyOoniOoh6SE/lJ0SqF1VWvDj9qbXnZT/Vtp90PB5QaJ+15tWlmBSK7JUSMVBEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAABEAgXwj8P1QjL/BchIZ8AAAAAElFTkSuQmCC
Process finished with exit code 0
(1)PBKDF2算法
PBKDF2算法通过多次hash来对密码进行加密
。
原理是通过password和
salt进行hash,然后将结果作为salt在与password进行hash,多次重复此过程,生成最终的密文。
此过程可能达到上千次,逆向破解的难度太大,破解一个密码的时间可能需要几百年,所以PBKDF2算法是安全的.
使用PBKDF2
算法时,HASH算法一般选用sha1或者sha256
,随机盐的长度一般不能少于8字节,HASH次数至少也要1000次
,这样安全性才足够高。一次密码验证过程进行1000次HASH运算,对服务器来说可能只需要1ms,但对于破解者来说计算成本增加了1000倍,而至少8字节随机盐,更是把建表难度提升了N个数量级,使得大批量的破解密码几乎不可行,该算法也是美国国家标准与技术研究院推荐使用的算法。
(2)如何验证密码正确?
用相同的盐值对用户输入的密码进行加密,如果与密文比对,相同则密码正确。
(3)加盐处理
在密码学中,是指通过在密码任意固定位置插入特定的字符串,让散列后的结果和使用原始密码的散列结果不相符,这种过程称之为“加盐”(比如可以在密码中混入一段“随机”的字符串再进行哈希加密,这个被字符串被称作盐值
)。
(4)为什么要加盐
涉及身份验证的系统都需要存储用户的认证信息,常用的用户认证方式主要为用户名和密码的方式,为了安全起见,用户输入的密码需要保存为密文形式,可采用已公开的
不可逆的hash加密算法
,比如SHA256, SHA512,SHA3等
,对于同一密码,同一加密算法会产生相同的hash值,这样,当用户进行身份验证时,也可对用户输入的明文密码应用相同的hash加密算法,得出一个hash值,然后使用该hash值和之前存储好的密文值进行对照,如果两个值相同,则密码认证成功,否则密码认证失败.
由于密码是由用户设定的,在实际应用中,用户设置的密码复杂度可能不够高,同时不同的用户极有可能会使用相同的密码,那么这些用户对应的密文也会相同,这样,当存储用户密码的数据库泄露后,攻击者会很容易便能找到相同密码的用户,从而也降低了破解密码的难度,因此,在对用户密码进行加密时,需要考虑对密码进行掩饰,即使是相同的密码,也应该要保存为不同的密文,即使用户输入的是弱密码,也需要考虑进行增强,从而增加密码被攻破的难度,而使用带盐的加密hash值便能满足该需求。
PBKDF2加密工具:
package utils;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
/**
* PBKDF2加密工具
* @author qzz
*/
public class PBKDF2Util {
/**
* 算法
*/
public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
/**
* 盐的长度
*/
public static final int SALT_BYTE_SIZE = 16;
/**
* 生成密文的长度
*/
public static final int HASH_BIT_SIZE = 128 * 4;
/**
* 迭代次数
*/
public static final int PBKDF2_ITERATIONS = 1000;
/**
* @describe: 对输入的密码进行验证
* @param: [attemptedPassword(待验证密码), encryptedPassword(密文), salt(盐值)]
* @return: boolean
*/
private static boolean authenticate(String attemptedPassword, String encryptedPassword, String salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
// 用相同的盐值对用户输入的密码进行加密
String encryptedAttemptedPassword = getEncryptedPassword(attemptedPassword, salt);
// 把加密后的密文和原密文进行比较,相同则验证成功,否则失败
return encryptedAttemptedPassword.equals(encryptedPassword);
}
/**
* @describe: 生成密文
* @param: [password(明文密码), salt(盐值)]
* @return: java.lang.String
*/
private static String getEncryptedPassword(String password, String salt) throws NoSuchAlgorithmException,
InvalidKeySpecException {
//参数 :明文密码 ,盐值,和迭代次数和长度生成密文
KeySpec spec = new PBEKeySpec(password.toCharArray(), fromHex(salt), PBKDF2_ITERATIONS, HASH_BIT_SIZE);
//返回转换指定算法的秘密密钥的 SecretKeyFactory 对象
//此方法从首选 Provider 开始遍历已注册安全提供者列表。返回一个封装 SecretKeyFactorySpi 实现的新 SecretKeyFactory 对象,该实现取自支持指定算法的第一个 Provider。
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
//根据提供的密钥规范(密钥材料)生成 SecretKey 对象。 然后以主要编码格式返回键,最后转换为16进制字符串
return toHex(factory.generateSecret(spec).getEncoded());
}
/**
* @describe: 通过加密的强随机数生成盐(最后转换为16进制)
* @return: java.lang.String
*/
private static String generateSalt() throws NoSuchAlgorithmException {
//返回一个实现指定的 SecureRandom 对象
//随机数生成器 (RNG) 算法。
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
//生成盐
byte[] salt = new byte[SALT_BYTE_SIZE];
random.nextBytes(salt);
//返回16进制的字符串
return toHex(salt);
}
/**
* @describe: 十六进制字符串转二进制字符串
* @param: [hex]
* @return: byte[]
*/
private static byte[] fromHex(String hex) {
byte[] binary = new byte[hex.length() / 2];
for (int i = 0; i < binary.length; i++) {
binary[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
}
return binary;
}
/**
* @describe: 二进制字符串转十六进制字符串
* @param: [array]
* @return: java.lang.String
*/
private static String toHex(byte[] array) {
BigInteger bigInteger = new BigInteger(1, array);
String hex = bigInteger.toString(16);
int paddingLength = (array.length * 2) - hex.length();
if (paddingLength > 0) {
return String.format("%0" + paddingLength + "d", 0) + hex;
} else {
return hex;
}
}
/**
* 生成可以保存的数据
* @param password 明文
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static String generateStorngPasswordHash(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
//先获取盐值
String salt = PBKDF2Util.generateSalt();
//生成密文
String hash =PBKDF2Util.getEncryptedPassword(password,salt);
return salt + ":" + hash;
}
/**
* 明文密码和数据库保存的值比较
* @param originalPassword 明文密码
* @param storedPassword 数据库保存的值
* @throws NoSuchAlgorithmException
* @throws InvalidKeySpecException
*/
public static boolean validatePassword(String originalPassword, String storedPassword) throws NoSuchAlgorithmException, InvalidKeySpecException {
String[] parts = storedPassword.split(":");
String salt = parts[0];
String hash = parts[1];
return PBKDF2Util.authenticate(originalPassword,hash,salt);
}
}
测试使用:
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException {
//---------------------------加密-------------------------------
//原始密码
String password="123456";
System.out.println("原始密码:"+password);
//生成的可以保存的数据
String storedPassword=PBKDF2Util.generateStorngPasswordHash(password);
System.out.println("生成的可以保存的数据:"+storedPassword);
String[] parts = storedPassword.split(":");
String salt = parts[0];
String hash = parts[1];
System.out.println("盐值:"+salt);
System.out.println("加密后的密码:"+hash);
//---------------------------加密-------------------------------
//---------------------------校验-------------------------------
//明文密码
String originalPassword="1234156";
//数据库保存的值
String storedPassword2=storedPassword;
boolean isSuccess=PBKDF2Util.validatePassword(originalPassword,storedPassword2);
System.out.println("验证结果:"+isSuccess);
}
执行结果:
"D:\Program Files\Java\jdk1.8.0_40\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=55260:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_40\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\rt.jar;F:\study-project\password-validate\target\classes;D:\mvnrepository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-web\2.7.2\spring-boot-starter-web-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter\2.7.2\spring-boot-starter-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot\2.7.2\spring-boot-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-autoconfigure\2.7.2\spring-boot-autoconfigure-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-logging\2.7.2\spring-boot-starter-logging-2.7.2.jar;D:\mvnrepository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\mvnrepository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\mvnrepository\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;D:\mvnrepository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\mvnrepository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\mvnrepository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\mvnrepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\mvnrepository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\mvnrepository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\mvnrepository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-json\2.7.2\spring-boot-starter-json-2.7.2.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-databind\2.13.3\jackson-databind-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-annotations\2.13.3\jackson-annotations-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-core\2.13.3\jackson-core-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.3\jackson-datatype-jdk8-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.3\jackson-datatype-jsr310-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.3\jackson-module-parameter-names-2.13.3.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-tomcat\2.7.2\spring-boot-starter-tomcat-2.7.2.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.65\tomcat-embed-core-9.0.65.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.65\tomcat-embed-el-9.0.65.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.65\tomcat-embed-websocket-9.0.65.jar;D:\mvnrepository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\mvnrepository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\mvnrepository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\mvnrepository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\mvnrepository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\mvnrepository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar" utils.PBKDF2Util
原始密码:123456
生成的可以保存的数据:43cde27428c726f7bb6f4aa1621be967:5197e1bdfadace22f3afc35dfe53880130c01eb6d34dedc1700f592025e8922a6429a4866aa1c2c4245e5a43041ba7c7ff8cf5ddbc39920f88666051d1a64319
盐值:43cde27428c726f7bb6f4aa1621be967
加密后的密码:5197e1bdfadace22f3afc35dfe53880130c01eb6d34dedc1700f592025e8922a6429a4866aa1c2c4245e5a43041ba7c7ff8cf5ddbc39920f88666051d1a64319
验证结果:false
Process finished with exit code 0
pdkdf2_sha256加密验证算法工具类:
package utils;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Base64;
import java.util.Random;
/**
* pdkdf2_sha256 加密验证算法
* @author qzz
*/
public class Pbkdf2Sha256 {
/**
* 默认迭代次数
*/
private static final Integer DEFAULT_ITERATIONS=30000;
/**
* 算法名称
*/
private static final String algorithm="pdkdf2_sha256";
/**
* 获取密文
* @param password 密码明文
* @param salt 加盐
* @param iterations 迭代次数
* @return
*/
public static String getEncodedHash(String password,String salt,int iterations){
SecretKeyFactory keyFactory=null;
try {
keyFactory=SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
} catch (NoSuchAlgorithmException e) {
//无法检索 PBKDF2WithHmacSHA256 算法
System.err.println("Could not retrieve PBKDF2WithHmacSHA256 algorithm");
System.exit(1);
}
KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt.getBytes(StandardCharsets.UTF_8),iterations,256);
SecretKey secretKey = null;
try {
secretKey = keyFactory.generateSecret(keySpec);
} catch (InvalidKeySpecException e) {
//无法生成密钥
System.out.println("Could not generate secret key");
e.printStackTrace();
}
byte[] rawHash=secretKey.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);
}
/**
* rand salt
* iterations is default 30000
* @param password
* @return
*/
public static String encode(String password){
return encode(password,getSalt());
}
/**
* iterations is default 30000
* @param password
* @param salt
* @return
*/
public static String encode(String password,String salt){
return encode(password,salt,DEFAULT_ITERATIONS);
}
/**
*
* @param password 密码明文
* @param salt 加盐
* @param iterations 迭代次数
* @return
*/
public static String encode(String password,String salt,int iterations){
//获取密文
String hash=getEncodedHash(password,salt,iterations);
//返回字符串组装后的结果集:算法$迭代次数$盐值$密文$
return String.format("%s$%d$%s$%s",algorithm,iterations,salt,hash);
}
/**
* rand salt
* @param password
* @param iterations
* @return
*/
public static String encode(String password,int iterations){
return encode(password,getSalt(),iterations);
}
/**
* 校验密码是否合法
* @param password 明文
* @param hashedPassword 密文
* @return
*/
public static boolean verification(String password,String hashedPassword){
//将密文截取 parts[0]:算法 parts[1]:迭代次数 parts[2]:盐值 parts[3]:密文
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 password="111111";
System.out.println("明文密码:"+password);
//迭代次数
Integer iterations =1000;
//明文转密文(密文由四部分组成)
String hashedPassword=Pbkdf2Sha256.encode(password,iterations);
System.out.println("生成的可以保存的数据:"+hashedPassword);
//获取盐值
String[] parts = hashedPassword.split("\\$");
String salt=parts[2];
System.out.println("盐值:"+salt);
//待验证的明文
String password1="111111";
//密文校验
String hash=Pbkdf2Sha256.encode(password1,salt,iterations);
boolean isSuccess = hash.equals(hashedPassword);
System.out.println("验证结果:"+isSuccess);
}
执行结果:
"D:\Program Files\Java\jdk1.8.0_40\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=60197:C:\Program Files\JetBrains\IntelliJ IDEA 2021.1.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_40\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_40\jre\lib\rt.jar;F:\study-project\password-validate\target\classes;D:\mvnrepository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-web\2.7.2\spring-boot-starter-web-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter\2.7.2\spring-boot-starter-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot\2.7.2\spring-boot-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-autoconfigure\2.7.2\spring-boot-autoconfigure-2.7.2.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-logging\2.7.2\spring-boot-starter-logging-2.7.2.jar;D:\mvnrepository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\mvnrepository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\mvnrepository\org\slf4j\slf4j-api\1.7.32\slf4j-api-1.7.32.jar;D:\mvnrepository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\mvnrepository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\mvnrepository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\mvnrepository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\mvnrepository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\mvnrepository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\mvnrepository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-json\2.7.2\spring-boot-starter-json-2.7.2.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-databind\2.13.3\jackson-databind-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-annotations\2.13.3\jackson-annotations-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\core\jackson-core\2.13.3\jackson-core-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.3\jackson-datatype-jdk8-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.3\jackson-datatype-jsr310-2.13.3.jar;D:\mvnrepository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.3\jackson-module-parameter-names-2.13.3.jar;D:\mvnrepository\org\springframework\boot\spring-boot-starter-tomcat\2.7.2\spring-boot-starter-tomcat-2.7.2.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-core\9.0.65\tomcat-embed-core-9.0.65.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-el\9.0.65\tomcat-embed-el-9.0.65.jar;D:\mvnrepository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.65\tomcat-embed-websocket-9.0.65.jar;D:\mvnrepository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\mvnrepository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\mvnrepository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\mvnrepository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\mvnrepository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\mvnrepository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar" utils.Pbkdf2Sha256
明文密码:111111
生成的可以保存的数据:pdkdf2_sha256$1000$zC38kS8N4fqM$ZZhIo303sDRjPFycIlz2NlOiuxSzJkfGAfYx5Bj+iv8=
盐值:zC38kS8N4fqM
验证结果:true
Process finished with exit code 0
点击此处下载