diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5dcbd7d6c..6b5fd4098 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,11 +3,13 @@
-------------------------------------------------------------------------------------------------------------
-# 5.5.2 (2020-11-16)
+# 5.5.2 (2020-11-17)
### 新特性
+* 【crypto 】 KeyUtil增加重载,AES构造增加重载(issue#I25NNZ@Gitee)
### Bug修复
+* 【cron 】 修复CronTimer可能死循环的问题(issue#1224@Github)
-------------------------------------------------------------------------------------------------------------
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 32c70372a..2e77c2818 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
@@ -71,7 +71,7 @@ public class RandomUtil {
}
/**
- * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
+ * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
* 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator)
*
*
@@ -81,11 +81,31 @@ public class RandomUtil {
* @since 3.1.2
*/
public static SecureRandom getSecureRandom() {
+ return getSecureRandom(null);
+ }
+
+ /**
+ * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
+ * 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator)
+ *
+ *
+ * 相关说明见:https://stackoverflow.com/questions/137212/how-to-solve-slow-java-securerandom
+ *
+ * @param seed 随机数种子
+ * @return {@link SecureRandom}
+ * @since 5.5.2
+ */
+ public static SecureRandom getSecureRandom(byte[] seed) {
+ SecureRandom random;
try {
- return SecureRandom.getInstance("SHA1PRNG");
+ random = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
throw new UtilException(e);
}
+ if(null != seed){
+ random.setSeed(seed);
+ }
+ return random;
}
/**
diff --git a/hutool-cron/src/main/java/cn/hutool/cron/CronTimer.java b/hutool-cron/src/main/java/cn/hutool/cron/CronTimer.java
index d25c92add..ead9b3633 100644
--- a/hutool-cron/src/main/java/cn/hutool/cron/CronTimer.java
+++ b/hutool-cron/src/main/java/cn/hutool/cron/CronTimer.java
@@ -55,6 +55,9 @@ public class CronTimer extends Thread implements Serializable {
//执行点,时间记录为执行开始的时间,而非结束时间
thisTime = System.currentTimeMillis();
spawnLauncher(thisTime);
+ } else{
+ // 非正常时间重新计算(issue#1224@Github)
+ thisTime = System.currentTimeMillis();
}
}
log.debug("Hutool-cron timer stopped.");
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java
index 27402d5da..8defe591f 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/KeyUtil.java
@@ -5,7 +5,6 @@ import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharUtil;
-import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
@@ -108,22 +107,43 @@ public class KeyUtil {
}
/**
- * 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
+ * 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
+ * 当指定keySize<0时,AES默认长度为128,其它算法不指定。
*
* @param algorithm 算法,支持PBE算法
- * @param keySize 密钥长度
+ * @param keySize 密钥长度,<0表示不设定密钥长度,即使用默认长度
* @return {@link SecretKey}
* @since 3.1.2
*/
public static SecretKey generateKey(String algorithm, int keySize) {
+ return generateKey(algorithm, keySize, null);
+ }
+
+ /**
+ * 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
+ * 当指定keySize<0时,AES默认长度为128,其它算法不指定。
+ *
+ * @param algorithm 算法,支持PBE算法
+ * @param keySize 密钥长度,<0表示不设定密钥长度,即使用默认长度
+ * @param random 随机数生成器,null表示默认
+ * @return {@link SecretKey}
+ * @since 5.5.2
+ */
+ public static SecretKey generateKey(String algorithm, int keySize, SecureRandom random) {
algorithm = getMainAlgorithm(algorithm);
final KeyGenerator keyGenerator = getKeyGenerator(algorithm);
- if (keySize > 0) {
- keyGenerator.init(keySize);
- } else if (SymmetricAlgorithm.AES.getValue().equals(algorithm)) {
+ if (keySize <= 0 && SymmetricAlgorithm.AES.getValue().equals(algorithm)) {
// 对于AES的密钥,除非指定,否则强制使用128位
- keyGenerator.init(128);
+ keySize = 128;
+ }
+
+ if(keySize > 0){
+ if (null == random) {
+ keyGenerator.init(keySize);
+ } else {
+ keyGenerator.init(keySize, random);
+ }
}
return keyGenerator.generateKey();
}
@@ -140,7 +160,7 @@ public class KeyUtil {
SecretKey secretKey;
if (algorithm.startsWith("PBE")) {
// PBE密钥
- secretKey = generatePBEKey(algorithm, (null == key) ? null : StrUtil.str(key, CharsetUtil.CHARSET_UTF_8).toCharArray());
+ secretKey = generatePBEKey(algorithm, (null == key) ? null : StrUtil.utf8Str(key).toCharArray());
} else if (algorithm.startsWith("DES")) {
// DES密钥
secretKey = generateDESKey(algorithm, key);
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 4b34b67e1..909f0375a 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
@@ -2,9 +2,9 @@ package cn.hutool.crypto.symmetric;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
-import cn.hutool.crypto.SecureUtil;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
@@ -49,6 +49,16 @@ public class AES extends SymmetricCrypto {
super(SymmetricAlgorithm.AES, key);
}
+ /**
+ * 构造,使用默认的AES/ECB/PKCS5Padding
+ *
+ * @param key 密钥
+ * @since 5.5.2
+ */
+ public AES(SecretKey key) {
+ super(SymmetricAlgorithm.AES, key);
+ }
+
/**
* 构造,使用随机密钥
*
@@ -152,7 +162,7 @@ public class AES extends SymmetricCrypto {
*/
public AES(String mode, String padding, byte[] key, byte[] iv) {
this(mode, padding,//
- SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue(), key),//
+ KeyUtil.generateKey(SymmetricAlgorithm.AES.getValue(), key),//
ArrayUtil.isEmpty(iv) ? null : new IvParameterSpec(iv));
}
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 fdc994ecb..5ca621f57 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
@@ -134,7 +134,7 @@ public class SymmetricCrypto implements Serializable {
*
* @param algorithm 算法
* @param key 密钥,如果为null
自动生成一个key
- * @return {@link SymmetricCrypto}的子对象,即子对象自身
+ * @return SymmetricCrypto的子对象,即子对象自身
*/
public SymmetricCrypto init(String algorithm, SecretKey key) {
Assert.notBlank(algorithm, "'algorithm' must be not blank !");
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java
index a16d4f562..45bd03330 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java
@@ -1,13 +1,12 @@
package cn.hutool.crypto.test.asymmetric;
import cn.hutool.core.map.MapUtil;
-import org.junit.Assert;
-import org.junit.Test;
-
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.Sign;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
+import org.junit.Assert;
+import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
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 4df4defcf..4137a3c1d 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
@@ -2,12 +2,17 @@ package cn.hutool.crypto.test.symmetric;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import org.junit.Assert;
import org.junit.Test;
+import javax.crypto.SecretKey;
+import java.security.SecureRandom;
+
public class AESTest {
@Test
@@ -95,4 +100,17 @@ public class AESTest {
Assert.assertEquals("16c5", aes.decryptStr(Base64.decode("ecIQ0+MEkyz56mqciHxtfA==")));
// ------------------------------------------------------------------------
}
+
+ @Test
+ public void aesWithSha1PrngTest() {
+ final SecureRandom random = RandomUtil.getSecureRandom("123456".getBytes());
+ final SecretKey secretKey = KeyUtil.generateKey("AES", 128, random);
+
+ String content = "12sdfsdfs你好啊!";
+ AES aes = new AES(secretKey);
+ final String result1 = aes.encryptBase64(content);
+
+ final String decryptStr = aes.decryptStr(result1);
+ Assert.assertEquals(content, decryptStr);
+ }
}