diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84418d6f5..b666f7308 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@
* 【core 】 增加DefaultCloneable(pr#459@Gitee)
* 【core 】 CollStreamUtil增加是否并行的重载(pr#467@Gitee)
* 【core 】 ResourceClassLoader增加缓存(pr#1959@Github)
+* 【crypto 】 增加CipherWrapper,增加setRandom(pr#1959@Github)
*
### 🐞Bug修复
* 【core 】 修复FileResource构造fileName参数无效问题(issue#1942@Github)
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/CipherWrapper.java b/hutool-crypto/src/main/java/cn/hutool/crypto/CipherWrapper.java
new file mode 100644
index 000000000..bb9a2578a
--- /dev/null
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/CipherWrapper.java
@@ -0,0 +1,121 @@
+package cn.hutool.crypto;
+
+import javax.crypto.Cipher;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * {@link Cipher}包装类,提供初始化模式等额外方法
+ * 包装之后可提供自定义或默认的:
+ *
+ * - {@link AlgorithmParameterSpec}
+ * - {@link SecureRandom}
+ *
+ *
+ * @author looly
+ * @since 5.7.17
+ */
+public class CipherWrapper {
+
+ private final Cipher cipher;
+ /**
+ * 算法参数
+ */
+ private AlgorithmParameterSpec params;
+ /**
+ * 随机数生成器,可自定义随机数种子
+ */
+ private SecureRandom random;
+
+ /**
+ * 构造
+ *
+ * @param algorithm 算法名称
+ */
+ public CipherWrapper(String algorithm) {
+ this(SecureUtil.createCipher(algorithm));
+ }
+
+ /**
+ * 构造
+ *
+ * @param cipher {@link Cipher}
+ */
+ public CipherWrapper(Cipher cipher) {
+ this.cipher = cipher;
+ }
+
+ /**
+ * 获取{@link AlgorithmParameterSpec}
+ * 在某些算法中,需要特别的参数,例如在ECIES中,此处为IESParameterSpec
+ *
+ * @return {@link AlgorithmParameterSpec}
+ */
+ public AlgorithmParameterSpec getParams() {
+ return this.params;
+ }
+
+ /**
+ * 设置 {@link AlgorithmParameterSpec},通常用于加盐或偏移向量
+ *
+ * @param params {@link AlgorithmParameterSpec}
+ * @return this
+ */
+ public CipherWrapper setParams(AlgorithmParameterSpec params) {
+ this.params = params;
+ return this;
+ }
+
+ /**
+ * 设置随机数生成器,可自定义随机数种子
+ *
+ * @param random 随机数生成器,可自定义随机数种子
+ * @return this
+ */
+ public CipherWrapper setRandom(SecureRandom random) {
+ this.random = random;
+ return this;
+ }
+
+ /**
+ * 获取被包装的{@link Cipher}
+ *
+ * @return {@link Cipher}
+ */
+ public Cipher getCipher() {
+ return this.cipher;
+ }
+
+ /**
+ * 初始化{@link Cipher}为加密或者解密模式
+ *
+ * @param mode 模式,见{@link Cipher#ENCRYPT_MODE} 或 {@link Cipher#DECRYPT_MODE}
+ * @param key 密钥
+ * @return this
+ * @throws InvalidKeyException 无效key
+ * @throws InvalidAlgorithmParameterException 无效算法
+ */
+ public CipherWrapper initMode(int mode, Key key)
+ throws InvalidKeyException, InvalidAlgorithmParameterException {
+ final Cipher cipher = this.cipher;
+ final AlgorithmParameterSpec params = this.params;
+ final SecureRandom random = this.random;
+ if (null != params) {
+ if (null != random) {
+ cipher.init(mode, key, params, random);
+ } else {
+ cipher.init(mode, key, params);
+ }
+ } else {
+ if (null != random) {
+ cipher.init(mode, key, random);
+ } else {
+ cipher.init(mode, key);
+ }
+ }
+ return this;
+ }
+}
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java
index 22198e58a..25f5661c4 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/AsymmetricCrypto.java
@@ -2,6 +2,7 @@ package cn.hutool.crypto.asymmetric;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FastByteArrayOutputStream;
+import cn.hutool.crypto.CipherWrapper;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
@@ -16,6 +17,7 @@ import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
/**
@@ -37,7 +39,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
/**
* Cipher负责完成加密或解密工作
*/
- protected Cipher cipher;
+ protected CipherWrapper cipherWrapper;
/**
* 加密的块大小
@@ -47,12 +49,6 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* 解密的块大小
*/
protected int decryptBlockSize = -1;
-
- /**
- * 算法参数
- */
- private AlgorithmParameterSpec algorithmParameterSpec;
-
// ------------------------------------------------------------------ Constructor start
/**
@@ -201,7 +197,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 5.4.3
*/
public AlgorithmParameterSpec getAlgorithmParameterSpec() {
- return algorithmParameterSpec;
+ return this.cipherWrapper.getParams();
}
/**
@@ -212,7 +208,19 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 5.4.3
*/
public void setAlgorithmParameterSpec(AlgorithmParameterSpec algorithmParameterSpec) {
- this.algorithmParameterSpec = algorithmParameterSpec;
+ this.cipherWrapper.setParams(algorithmParameterSpec);
+ }
+
+ /**
+ * 设置随机数生成器,可自定义随机数种子
+ *
+ * @param random 随机数生成器,可自定义随机数种子
+ * @return this
+ * @since 5.7.17
+ */
+ public AsymmetricCrypto setRandom(SecureRandom random) {
+ this.cipherWrapper.setRandom(random);
+ return this;
}
@Override
@@ -229,11 +237,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
final Key key = getKeyByType(keyType);
lock.lock();
try {
- initMode(Cipher.ENCRYPT_MODE, key);
+ final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, key);
if (this.encryptBlockSize < 0) {
// 在引入BC库情况下,自动获取块大小
- final int blockSize = this.cipher.getBlockSize();
+ final int blockSize = cipher.getBlockSize();
if (blockSize > 0) {
this.encryptBlockSize = blockSize;
}
@@ -254,11 +262,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
final Key key = getKeyByType(keyType);
lock.lock();
try {
- initMode(Cipher.DECRYPT_MODE, key);
+ final Cipher cipher = initMode(Cipher.DECRYPT_MODE, key);
if (this.decryptBlockSize < 0) {
// 在引入BC库情况下,自动获取块大小
- final int blockSize = this.cipher.getBlockSize();
+ final int blockSize = cipher.getBlockSize();
if (blockSize > 0) {
this.decryptBlockSize = blockSize;
}
@@ -281,7 +289,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 5.4.3
*/
public Cipher getCipher() {
- return cipher;
+ return this.cipherWrapper.getCipher();
}
/**
@@ -290,7 +298,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @since 4.5.2
*/
protected void initCipher() {
- this.cipher = SecureUtil.createCipher(algorithm);
+ this.cipherWrapper = new CipherWrapper(this.algorithm);
}
/**
@@ -309,7 +317,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
// 不足分段
if (dataLength <= maxBlockSize) {
- return this.cipher.doFinal(data, 0, dataLength);
+ return getCipher().doFinal(data, 0, dataLength);
}
// 分段解密
@@ -337,7 +345,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
// 对数据分段处理
while (remainLength > 0) {
blockSize = Math.min(remainLength, maxBlockSize);
- out.write(cipher.doFinal(data, offSet, blockSize));
+ out.write(getCipher().doFinal(data, offSet, blockSize));
offSet += blockSize;
remainLength = dataLength - offSet;
@@ -351,14 +359,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
*
* @param mode 模式,可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE}
* @param key 密钥
+ * @return {@link Cipher}
* @throws InvalidAlgorithmParameterException 异常算法错误
* @throws InvalidKeyException 异常KEY错误
*/
- private void initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
- if (null != this.algorithmParameterSpec) {
- cipher.init(mode, key, this.algorithmParameterSpec);
- } else {
- cipher.init(mode, key);
- }
+ private Cipher initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
+ return this.cipherWrapper.initMode(mode, key).getCipher();
}
}
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricCrypto.java b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricCrypto.java
index ba92ab553..ea4a7756d 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricCrypto.java
@@ -3,15 +3,16 @@ package cn.hutool.crypto.symmetric;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
+import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.CipherMode;
+import cn.hutool.crypto.CipherWrapper;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Padding;
-import cn.hutool.crypto.SecureUtil;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
@@ -25,6 +26,7 @@ import java.io.OutputStream;
import java.io.Serializable;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
+import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@@ -40,18 +42,11 @@ import java.util.concurrent.locks.ReentrantLock;
public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, Serializable {
private static final long serialVersionUID = 1L;
+ private CipherWrapper cipherWrapper;
/**
* SecretKey 负责保存对称密钥
*/
private SecretKey secretKey;
- /**
- * Cipher负责完成加密或解密工作
- */
- private Cipher cipher;
- /**
- * 加密解密参数
- */
- private AlgorithmParameterSpec params;
/**
* 是否0填充
*/
@@ -152,7 +147,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
this.isZeroPadding = true;
}
- this.cipher = SecureUtil.createCipher(algorithm);
+ this.cipherWrapper = new CipherWrapper(algorithm);
return this;
}
@@ -171,7 +166,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 加密或解密
*/
public Cipher getCipher() {
- return cipher;
+ return cipherWrapper.getCipher();
}
/**
@@ -181,7 +176,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setParams(AlgorithmParameterSpec params) {
- this.params = params;
+ this.cipherWrapper.setParams(params);
return this;
}
@@ -192,8 +187,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setIv(IvParameterSpec iv) {
- setParams(iv);
- return this;
+ return setParams(iv);
}
/**
@@ -203,7 +197,18 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setIv(byte[] iv) {
- setIv(new IvParameterSpec(iv));
+ return setIv(new IvParameterSpec(iv));
+ }
+
+ /**
+ * 设置随机数生成器,可自定义随机数种子
+ *
+ * @param random 随机数生成器,可自定义随机数种子
+ * @return this
+ * @since 5.7.17
+ */
+ public SymmetricCrypto setRandom(SecureRandom random){
+ this.cipherWrapper.setRandom(random);
return this;
}
@@ -237,6 +242,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @since 5.6.8
*/
public byte[] update(byte[] data) {
+ final Cipher cipher = cipherWrapper.getCipher();
lock.lock();
try {
return cipher.update(paddingDataWithZero(data, cipher.getBlockSize()));
@@ -376,11 +382,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
*/
private SymmetricCrypto initParams(String algorithm, AlgorithmParameterSpec paramsSpec) {
if (null == paramsSpec) {
- byte[] iv = null;
- final Cipher cipher = this.cipher;
- if (null != cipher) {
- iv = cipher.getIV();
- }
+ byte[] iv = Opt.ofNullable(cipherWrapper)
+ .map(CipherWrapper::getCipher).map(Cipher::getIV).get();
// 随机IV
if (StrUtil.startWithIgnoreCase(algorithm, "PBE")) {
@@ -409,13 +412,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @throws InvalidAlgorithmParameterException 无效算法
*/
private Cipher initMode(int mode) throws InvalidKeyException, InvalidAlgorithmParameterException {
- final Cipher cipher = this.cipher;
- if (null == this.params) {
- cipher.init(mode, secretKey);
- } else {
- cipher.init(mode, secretKey, params);
- }
- return cipher;
+ return this.cipherWrapper.initMode(mode, this.secretKey).getCipher();
}
/**