diff --git a/CHANGELOG.md b/CHANGELOG.md index 15a28fb9c..a8c6f0685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * 【poi 】 重要:不再兼容POI-3.x,增加兼容POI-5.x(issue#I35J6B@Gitee) * 【core 】 FileTypeUtil使用长匹配优先(pr#1457@Github) * 【core 】 IterUtil和CollUtil增加isEqualList方法(issue#I3A3PY@Gitee) +* 【crypto 】 增加PBKDF2(issue#1416@Github) ### Bug修复 * 【socket 】 修复Client创建失败资源未释放问题。 diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/SecureUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/SecureUtil.java index ddb39e1ee..17c0da0f2 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/SecureUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/SecureUtil.java @@ -19,6 +19,7 @@ import cn.hutool.crypto.digest.MD5; import cn.hutool.crypto.symmetric.AES; import cn.hutool.crypto.symmetric.DES; import cn.hutool.crypto.symmetric.DESede; +import cn.hutool.crypto.symmetric.PBKDF2; import cn.hutool.crypto.symmetric.RC4; import cn.hutool.crypto.symmetric.SymmetricCrypto; @@ -1048,4 +1049,16 @@ public final class SecureUtil { public static void disableBouncyCastle() { GlobalBouncyCastleProvider.setUseBouncyCastle(false); } + + /** + * PBKDF2加密密码 + * + * @param password 密码 + * @param salt 盐 + * @return 盐,一般为16位 + * @since 5.6.0 + */ + public static String pbkdf2(char[] password, byte[] salt){ + return new PBKDF2().encryptHex(password, salt); + } } diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/PBKDF2.java b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/PBKDF2.java new file mode 100644 index 000000000..059660afe --- /dev/null +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/PBKDF2.java @@ -0,0 +1,66 @@ +package cn.hutool.crypto.symmetric; + +import cn.hutool.core.util.HexUtil; +import cn.hutool.crypto.KeyUtil; + +import javax.crypto.SecretKey; +import javax.crypto.spec.PBEKeySpec; + +/** + * PBKDF2应用一个伪随机函数以导出密钥,PBKDF2简单而言就是将salted hash进行多次重复计算。 + * 参考:https://blog.csdn.net/huoji555/article/details/83659687 + * + * @author looly + */ +public class PBKDF2 { + + private String algorithm = "PBKDF2WithHmacSHA1"; + //生成密文的长度 + private int keyLength = 512; + + //迭代次数 + private int iterationCount = 1000; + + /** + * 构造,算法PBKDF2WithHmacSHA1,盐长度16,密文长度512,迭代次数1000 + */ + public PBKDF2() { + } + + /** + * 构造 + * + * @param algorithm 算法,一般为PBKDF2WithXXX + * @param keyLength 生成密钥长度,默认512 + * @param iterationCount 迭代次数,默认1000 + */ + public PBKDF2(String algorithm, int keyLength, int iterationCount) { + this.algorithm = algorithm; + this.keyLength = keyLength; + this.iterationCount = iterationCount; + } + + /** + * 加密 + * + * @param password 密码 + * @param salt 盐 + * @return 加密后的密码 + */ + public byte[] encrypt(char[] password, byte[] salt) { + final PBEKeySpec pbeKeySpec = new PBEKeySpec(password, salt, iterationCount, keyLength); + final SecretKey secretKey = KeyUtil.generateKey(algorithm, pbeKeySpec); + return secretKey.getEncoded(); + } + + /** + * 加密 + * + * @param password 密码 + * @param salt 盐 + * @return 加密后的密码 + */ + public String encryptHex(char[] password, byte[] salt) { + return HexUtil.encodeHexStr(encrypt(password, salt)); + } +} diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/PBKDF2Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/PBKDF2Test.java new file mode 100644 index 000000000..780781ee2 --- /dev/null +++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/PBKDF2Test.java @@ -0,0 +1,15 @@ +package cn.hutool.crypto.test.symmetric; + +import cn.hutool.core.util.RandomUtil; +import cn.hutool.crypto.SecureUtil; +import org.junit.Assert; +import org.junit.Test; + +public class PBKDF2Test { + + @Test + public void encryptTest(){ + final String s = SecureUtil.pbkdf2("123456".toCharArray(), RandomUtil.randomBytes(16)); + Assert.assertEquals(128, s.length()); + } +}