浏览代码

add method

Looly 5 年之前
父节点
当前提交
11e6a28113

+ 3 - 1
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)
 
 -------------------------------------------------------------------------------------------------------------
 

+ 22 - 2
hutool-core/src/main/java/cn/hutool/core/util/RandomUtil.java

@@ -71,7 +71,7 @@ public class RandomUtil {
 	}
 
 	/**
-	 * 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)<br>
+	 * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)<br>
 	 * 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator)
 	 *
 	 * <p>
@@ -81,11 +81,31 @@ public class RandomUtil {
 	 * @since 3.1.2
 	 */
 	public static SecureRandom getSecureRandom() {
+		return getSecureRandom(null);
+	}
+
+	/**
+	 * 获取SHA1PRNG的{@link SecureRandom},类提供加密的强随机数生成器 (RNG)<br>
+	 * 注意:此方法获取的是伪随机序列发生器PRNG(pseudo-random number generator)
+	 *
+	 * <p>
+	 * 相关说明见: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;
 	}
 
 	/**

+ 3 - 0
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.");

+ 28 - 8
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},仅用于对称加密和摘要算法密钥生成<br>
+	 * 当指定keySize&lt;0时,AES默认长度为128,其它算法不指定。
 	 *
 	 * @param algorithm 算法,支持PBE算法
-	 * @param keySize   密钥长度
+	 * @param keySize   密钥长度,&lt;0表示不设定密钥长度,即使用默认长度
 	 * @return {@link SecretKey}
 	 * @since 3.1.2
 	 */
 	public static SecretKey generateKey(String algorithm, int keySize) {
+		return generateKey(algorithm, keySize, null);
+	}
+
+	/**
+	 * 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成<br>
+	 * 当指定keySize&lt;0时,AES默认长度为128,其它算法不指定。
+	 *
+	 * @param algorithm 算法,支持PBE算法
+	 * @param keySize   密钥长度,&lt;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);

+ 12 - 2
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;
@@ -50,6 +50,16 @@ public class AES extends SymmetricCrypto {
 	}
 
 	/**
+	 * 构造,使用默认的AES/ECB/PKCS5Padding
+	 *
+	 * @param key 密钥
+	 * @since 5.5.2
+	 */
+	public AES(SecretKey key) {
+		super(SymmetricAlgorithm.AES, key);
+	}
+
+	/**
 	 * 构造,使用随机密钥
 	 *
 	 * @param mode    模式{@link Mode}
@@ -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));
 	}
 

+ 1 - 1
hutool-crypto/src/main/java/cn/hutool/crypto/symmetric/SymmetricCrypto.java

@@ -134,7 +134,7 @@ public class SymmetricCrypto implements Serializable {
 	 *
 	 * @param algorithm 算法
 	 * @param key       密钥,如果为<code>null</code>自动生成一个key
-	 * @return {@link SymmetricCrypto}的子对象,即子对象自身
+	 * @return SymmetricCrypto的子对象,即子对象自身
 	 */
 	public SymmetricCrypto init(String algorithm, SecretKey key) {
 		Assert.notBlank(algorithm, "'algorithm' must be not blank !");

+ 2 - 3
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;

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