diff --git a/CHANGELOG.md b/CHANGELOG.md
index 972213e19..a67f6a052 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@
* 【crypto 】 SymmetricCrypto增加setMode方法,update采用累加模式(pr#1642@Github)
* 【core 】 ZipReader支持Filter
* 【all 】 Sftp、Ftp、HttpDownloader增加download重载,支持避免传输文件损坏(pr#407@Gitee)
+* 【crypto 】 AES修改构造的IvParameterSpec为AlgorithmParameterSpec(issue#1814@Gitee)
### 🐞Bug修复
* 【core 】 修复ListUtil.split方法越界问题(issue#I48Q0P@Gitee)
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java
index b9a91db0e..aae07f8be 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java
@@ -125,6 +125,21 @@ public class RandomUtil {
return random;
}
+ /**
+ * 获取algorithms/providers中提供的强安全随机生成器
+ * 注意:此方法可能造成阻塞或性能问题
+ *
+ * @return {@link SecureRandom}
+ * @since 5.7.12
+ */
+ public static SecureRandom getSecureRandomStrong() {
+ try {
+ return SecureRandom.getInstanceStrong();
+ } catch (NoSuchAlgorithmException e) {
+ throw new UtilException(e);
+ }
+ }
+
/**
* 获取随机数产生器
*
diff --git a/hutool-core/src/main/java/cn/hutool/core/util/ReUtil.java b/hutool-core/src/main/java/cn/hutool/core/util/ReUtil.java
index 20ff64b82..fcad035a5 100644
--- a/hutool-core/src/main/java/cn/hutool/core/util/ReUtil.java
+++ b/hutool-core/src/main/java/cn/hutool/core/util/ReUtil.java
@@ -96,7 +96,7 @@ public class ReUtil {
}
/**
- * 获得匹配的字符串,,获得正则中分组1的内容
+ * 获得匹配的字符串,获得正则中分组1的内容
*
* @param pattern 编译后的正则模式
* @param content 被匹配的内容
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/AES.java b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/AES.java
index 566c28d6f..dc03596a5 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/AES.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/AES.java
@@ -8,6 +8,7 @@ import cn.hutool.crypto.Padding;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
+import java.security.spec.AlgorithmParameterSpec;
/**
* AES加密算法实现
@@ -121,14 +122,14 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
- * @param mode 模式{@link Mode}
- * @param padding {@link Padding}补码方式
- * @param key 密钥,支持三种密钥长度:128、192、256位
- * @param iv 偏移向量,加盐
+ * @param mode 模式{@link Mode}
+ * @param padding {@link Padding}补码方式
+ * @param key 密钥,支持三种密钥长度:128、192、256位
+ * @param paramsSpec 算法参数,例如加盐等
* @since 3.3.0
*/
- public AES(Mode mode, Padding padding, SecretKey key, IvParameterSpec iv) {
- this(mode.name(), padding.name(), key, iv);
+ public AES(Mode mode, Padding padding, SecretKey key, AlgorithmParameterSpec paramsSpec) {
+ this(mode.name(), padding.name(), key, paramsSpec);
}
/**
@@ -180,13 +181,13 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
- * @param mode 模式
- * @param padding 补码方式
- * @param key 密钥,支持三种密钥长度:128、192、256位
- * @param iv 加盐
+ * @param mode 模式
+ * @param padding 补码方式
+ * @param key 密钥,支持三种密钥长度:128、192、256位
+ * @param paramsSpec 算法参数,例如加盐等
*/
- public AES(String mode, String padding, SecretKey key, IvParameterSpec iv) {
- super(StrUtil.format("AES/{}/{}", mode, padding), key, iv);
+ public AES(String mode, String padding, SecretKey key, AlgorithmParameterSpec paramsSpec) {
+ super(StrUtil.format("AES/{}/{}", mode, padding), key, paramsSpec);
}
//------------------------------------------------------------------------- Constrctor end
}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java
index ba8ef1c6d..805f6e846 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java
@@ -7,10 +7,14 @@ import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
+import org.bouncycastle.crypto.util.BasicAlphabetMapper;
+import org.bouncycastle.jcajce.spec.FPEParameterSpec;
import org.junit.Assert;
import org.junit.Test;
import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
public class AESTest {
@@ -112,4 +116,51 @@ public class AESTest {
final String decryptStr = aes.decryptStr(result1);
Assert.assertEquals(content, decryptStr);
}
+
+ /**
+ * 见:https://github.com/dromara/hutool/issues/1814
+ */
+ @Test
+ public void fpeTest() {
+ // 映射字符表,规定了明文和密文的字符范围
+ BasicAlphabetMapper numberMapper = new BasicAlphabetMapper("0123456789");
+
+ // 初始化 aes 密钥
+ byte[] keyBytes = RandomUtil.randomBytes(16);
+
+ AES aes = new AES("FF1", "NoPadding",
+ new SecretKeySpec(keyBytes, "FF1"),
+ new FPEParameterSpec(numberMapper.getRadix(), new byte[]{}));
+
+ // 原始数据
+ String phone = "13534534567";
+ // 加密
+ byte[] inputDataByte = numberMapper.convertToIndexes(phone.toCharArray());
+ byte[] encrypt = aes.encrypt(inputDataByte);
+
+ // 通过 mapper 将密文输出处理为原始格式
+ char[] encryptChars = numberMapper.convertToChars(encrypt);
+ // 手机号码加密: 13534534567 -> 49725950626
+ Assert.assertEquals(phone.length(), encryptChars.length);
+ }
+
+ /**
+ * 见:https://blog.csdn.net/weixin_42468911/article/details/114358682
+ */
+ @Test
+ public void gcmTest() {
+ final SecretKey key = KeyUtil.generateKey("AES");
+ byte[] iv = RandomUtil.randomBytes(12);
+
+ AES aes = new AES("GCM", "NoPadding",
+ key,
+ new GCMParameterSpec(128, iv));
+
+ // 原始数据
+ String phone = "13534534567";
+ // 加密
+ byte[] encrypt = aes.encrypt(phone);
+ final String decryptStr = aes.decryptStr(encrypt);
+ Assert.assertEquals(phone, decryptStr);
+ }
}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ChaCha20Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ChaCha20Test.java
new file mode 100644
index 000000000..027cc241f
--- /dev/null
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ChaCha20Test.java
@@ -0,0 +1,38 @@
+package cn.hutool.crypto.test.symmetric;
+
+import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.crypto.KeyUtil;
+import cn.hutool.crypto.symmetric.SymmetricCrypto;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.crypto.spec.IvParameterSpec;
+
+/**
+ * 见:https://stackoverflow.com/questions/32672241/using-bouncycastles-chacha-for-file-encryption
+ */
+public class ChaCha20Test {
+
+ @Test
+ public void encryptAndDecryptTest() {
+ String content = "test中文";
+
+ // 32 for 256 bit key or 16 for 128 bit
+ byte[] key = RandomUtil.randomBytes(32);
+ // 64 bit IV required by ChaCha20
+ byte[] iv = RandomUtil.randomBytes(12);
+
+ final SymmetricCrypto chacha = new SymmetricCrypto("ChaCha20",
+ KeyUtil.generateKey("ChaCha", key),
+ new IvParameterSpec(iv)
+ );
+
+ // 加密为16进制表示
+ String encryptHex = chacha.encryptHex(content);
+ // 解密为字符串
+ String decryptStr = chacha.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
+
+ Assert.assertEquals(content, decryptStr);
+ }
+}