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); + } }