add ZeroPadding support

This commit is contained in:
Looly
2019-09-21 22:24:59 +08:00
parent 4292d3fd55
commit c9f77e1746
9 changed files with 362 additions and 161 deletions

View File

@@ -16,6 +16,8 @@
* 【cron】 添加获取任务表的方法issue#I12E5H@Gitee
* 【http】 SoapClient增加reset方法用于此对象的复用issue#I12CCC@Gitee
* 【db】 StatementUtil增加setParam方法
* 【db】 Entity.fieldList改为有序实现
* 【crypto】 AES、DES增加对ZeroPadding的支持issue#551@Github
### Bug修复
* 【core】 修复DateUtil.offset导致的时区错误问题issue#I1294O@Gitee

View File

@@ -1,15 +1,15 @@
package cn.hutool.core.util;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.*;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.lang.Editor;
import cn.hutool.core.lang.Filter;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.util.*;
/**
* 数组工具类
*
@@ -494,15 +494,63 @@ public class ArrayUtil {
* 调整大小后拷贝原数组到新数组下。扩大则占位前N个位置缩小则截断
*
* @param <T> 数组元素类型
* @param buffer 原数组
* @param data 原数组
* @param newSize 新的数组大小
* @param componentType 数组元素类型
* @return 调整后的新数组
*/
public static <T> T[] resize(T[] buffer, int newSize, Class<?> componentType) {
T[] newArray = newArray(componentType, newSize);
if (isNotEmpty(buffer)) {
System.arraycopy(buffer, 0, newArray, 0, Math.min(buffer.length, newSize));
public static <T> T[] resize(T[] data, int newSize, Class<?> componentType) {
if(newSize < 0){
return data;
}
final T[] newArray = newArray(componentType, newSize);
if (newSize > 0 && isNotEmpty(data)) {
System.arraycopy(data, 0, newArray, 0, Math.min(data.length, newSize));
}
return newArray;
}
/**
* 生成一个新的重新设置大小的数组<br>
* 调整大小后拷贝原数组到新数组下。扩大则占位前N个位置其它位置补充0缩小则截断
*
* @param array 原数组
* @param newSize 新的数组大小
* @return 调整后的新数组
* @since 4.6.7
*/
public static Object resize(Object array, int newSize) {
if(newSize < 0){
return array;
}
if (null == array) {
return null;
}
final int length = length(array);
final Object newArray = Array.newInstance(array.getClass().getComponentType(), newSize);
if (newSize > 0 && isNotEmpty(array)) {
System.arraycopy(array, 0, newArray, 0, Math.min(length, newSize));
}
return newArray;
}
/**
* 生成一个新的重新设置大小的数组<br>
* 调整大小后拷贝原数组到新数组下。扩大则占位前N个位置其它位置补充0缩小则截断
*
* @param bytes 原数组
* @param newSize 新的数组大小
* @return 调整后的新数组
* @since 4.6.7
*/
public static byte[] resize(byte[] bytes, int newSize) {
if(newSize < 0){
return bytes;
}
final byte[] newArray = new byte[newSize];
if (newSize > 0 && isNotEmpty(bytes)) {
System.arraycopy(bytes, 0, newArray, 0, Math.min(bytes.length, newSize));
}
return newArray;
}

View File

@@ -337,7 +337,7 @@ public class RandomUtil {
* @return 随机元素
*/
public static <T> List<T> randomEles(List<T> list, int count) {
final List<T> result = new ArrayList<T>(count);
final List<T> result = new ArrayList<>(count);
int limit = list.size();
while (result.size() < count) {
result.add(randomEle(list, limit));
@@ -361,7 +361,7 @@ public class RandomUtil {
throw new IllegalArgumentException("Count is larger than collection distinct size !");
}
final HashSet<T> result = new HashSet<T>(count);
final HashSet<T> result = new HashSet<>(count);
int limit = source.size();
while (result.size() < count) {
result.add(randomEle(source, limit));
@@ -409,14 +409,14 @@ public class RandomUtil {
* @return 随机字符串
*/
public static String randomString(String baseString, int length) {
final StringBuilder sb = new StringBuilder();
final StringBuilder sb = new StringBuilder(length);
if (length < 1) {
length = 1;
}
int baseLength = baseString.length();
for (int i = 0; i < length; i++) {
int number = getRandom().nextInt(baseLength);
int number = randomInt(baseLength);
sb.append(baseString.charAt(number));
}
return sb.toString();
@@ -450,7 +450,7 @@ public class RandomUtil {
* @since 3.1.2
*/
public static char randomChar(String baseString) {
return baseString.charAt(getRandom().nextInt(baseString.length()));
return baseString.charAt(randomInt(baseString.length()));
}
/**

View File

@@ -2,25 +2,45 @@ package cn.hutool.crypto;
/**
* 模式
*
* <p>
* 加密算法模式,是用来描述加密算法(此处特指分组密码,不包括流密码,)在加密时对明文分组的模式,它代表了不同的分组方式
*
* @author Looly
* @see <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Cipher"> Cipher章节</a>
* @since 3.0.8
*/
public enum Mode{
/** 无模式 */
public enum Mode {
/**
* 无模式
*/
NONE,
/** 密码分组连接模式Cipher Block Chaining */
/**
* 密码分组连接模式Cipher Block Chaining
*/
CBC,
/** 密文反馈模式Cipher Feedback */
/**
* 密文反馈模式Cipher Feedback
*/
CFB,
/** 计数器模式A simplification of OFB */
/**
* 计数器模式A simplification of OFB
*/
CTR,
/** Cipher Text Stealing */
/**
* Cipher Text Stealing
*/
CTS,
/** 电子密码本模式Electronic CodeBook */
/**
* 电子密码本模式Electronic CodeBook
*/
ECB,
/** 输出反馈模式Output Feedback */
/**
* 输出反馈模式Output Feedback
*/
OFB,
/** Propagating Cipher Block */
/**
* Propagating Cipher Block
*/
PCBC;
}

View File

@@ -3,13 +3,22 @@ package cn.hutool.crypto;
/**
* 补码方式
*
* <p>
* 补码方式是在分组密码中,当明文长度不是分组长度的整数倍时,需要在最后一个分组中填充一些数据使其凑满一个分组的长度。
*
* @author Looly
* @see <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Cipher"> Cipher章节</a>
* @since 3.0.8
*/
public enum Padding {
/** 无补码 */
/**
* 无补码
*/
NoPadding,
/**
* 0补码既不满block长度时使用0填充
*/
ZeroPadding,
ISO10126Padding,
OAEPPadding,
PKCS1Padding,

View File

@@ -3,6 +3,7 @@ package cn.hutool.crypto.symmetric;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
@@ -13,12 +14,24 @@ import cn.hutool.crypto.SecureUtil;
* 高级加密标准英语Advanced Encryption Standard缩写AES在密码学中又称Rijndael加密法<br>
* 对于Java中AES的默认模式是AES/ECB/PKCS5Padding如果使用CryptoJS请调整为padding: CryptoJS.pad.Pkcs7
*
* <p>
* 相关概念说明:
* <pre>
* mode: 加密算法模式,是用来描述加密算法(此处特指分组密码,不包括流密码,)在加密时对明文分组的模式,它代表了不同的分组方式
* padding: 补码方式是在分组密码中,当明文长度不是分组长度的整数倍时,需要在最后一个分组中填充一些数据使其凑满一个分组的长度。
* iv: 在对明文分组加密时会将明文分组与前一个密文分组进行XOR运算即异或运算但是加密第一个明文分组时不存在“前一个密文分组”
* 因此需要事先准备一个与分组长度相等的比特序列来代替,这个比特序列就是偏移量。
* </pre>
* <p>
* 相关概念见https://blog.csdn.net/OrangeJack/article/details/82913804
*
* @author Looly
* @since 3.0.8
*/
public class AES extends SymmetricCrypto {
//------------------------------------------------------------------------- Constrctor start
/**
* 构造默认AES/ECB/PKCS5Padding使用随机密钥
*/
@@ -38,7 +51,7 @@ public class AES extends SymmetricCrypto {
/**
* 构造,使用随机密钥
*
* @param mode 模式{@link Mode}
* @param mode 模式{@link Mode}
* @param padding {@link Padding}补码方式
*/
public AES(Mode mode, Padding padding) {
@@ -48,9 +61,9 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式{@link Mode}
* @param mode 模式{@link Mode}
* @param padding {@link Padding}补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param key 密钥支持三种密钥长度128、192、256位
*/
public AES(Mode mode, Padding padding, byte[] key) {
this(mode, padding, key, null);
@@ -59,10 +72,10 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式{@link Mode}
* @param mode 模式{@link Mode}
* @param padding {@link Padding}补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 偏移向量,加盐
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 偏移向量,加盐
* @since 3.3.0
*/
public AES(Mode mode, Padding padding, byte[] key, byte[] iv) {
@@ -72,22 +85,35 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式{@link Mode}
* @param mode 模式{@link Mode}
* @param padding {@link Padding}补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param key 密钥支持三种密钥长度128、192、256位
* @since 3.3.0
*/
public AES(Mode mode, Padding padding, SecretKey key) {
this(mode, padding, key, null);
this(mode, padding, key, (IvParameterSpec) null);
}
/**
* 构造
*
* @param mode 模式{@link Mode}
* @param mode 模式{@link Mode}
* @param padding {@link Padding}补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 偏移向量,加盐
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 偏移向量,加盐
* @since 4.6.7
*/
public AES(Mode mode, Padding padding, SecretKey key, byte[] iv) {
this(mode, padding, key, ArrayUtil.isEmpty(iv) ? ((IvParameterSpec) null) : new IvParameterSpec(iv));
}
/**
* 构造
*
* @param mode 模式{@link Mode}
* @param padding {@link Padding}补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 偏移向量,加盐
* @since 3.3.0
*/
public AES(Mode mode, Padding padding, SecretKey key, IvParameterSpec iv) {
@@ -97,7 +123,7 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式
* @param mode 模式
* @param padding 补码方式
*/
public AES(String mode, String padding) {
@@ -107,9 +133,9 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式
* @param mode 模式
* @param padding 补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param key 密钥支持三种密钥长度128、192、256位
*/
public AES(String mode, String padding, byte[] key) {
this(mode, padding, key, null);
@@ -118,21 +144,23 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式
* @param mode 模式
* @param padding 补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 加盐
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 加盐
*/
public AES(String mode, String padding, byte[] key, byte[] iv) {
this(mode, padding, SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue(), key), null == iv ? null : new IvParameterSpec(iv));
this(mode, padding,//
SecureUtil.generateKey(SymmetricAlgorithm.AES.getValue(), key),//
ArrayUtil.isEmpty(iv) ? ((IvParameterSpec) null) : new IvParameterSpec(iv));
}
/**
* 构造
*
* @param mode 模式
* @param mode 模式
* @param padding 补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param key 密钥支持三种密钥长度128、192、256位
*/
public AES(String mode, String padding, SecretKey key) {
this(mode, padding, key, null);
@@ -141,10 +169,10 @@ public class AES extends SymmetricCrypto {
/**
* 构造
*
* @param mode 模式
* @param mode 模式
* @param padding 补码方式
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 加盐
* @param key 密钥支持三种密钥长度128、192、256位
* @param iv 加盐
*/
public AES(String mode, String padding, SecretKey key, IvParameterSpec iv) {
super(StrUtil.format("AES/{}/{}", mode, padding), key, iv);

View File

@@ -1,26 +1,24 @@
package cn.hutool.crypto.symmetric;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.*;
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.SecretKey;
import javax.crypto.spec.PBEParameterSpec;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.security.spec.AlgorithmParameterSpec;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.PBEParameterSpec;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
/**
* 对称加密算法<br>
* 在对称加密算法中,数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。<br>
@@ -28,19 +26,29 @@ import cn.hutool.crypto.SecureUtil;
* 在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。<br>
*
* @author Looly
*
*/
public class SymmetricCrypto {
/** SecretKey 负责保存对称密钥 */
/**
* SecretKey 负责保存对称密钥
*/
private SecretKey secretKey;
/** Cipher负责完成加密或解密工作 */
/**
* Cipher负责完成加密或解密工作
*/
private Cipher cipher;
/** 加密解密参数 */
/**
* 加密解密参数
*/
private AlgorithmParameterSpec params;
/**
* 是否0填充
*/
private boolean isZeroPadding;
private Lock lock = new ReentrantLock();
// ------------------------------------------------------------------ Constructor start
/**
* 构造,使用随机密钥
*
@@ -63,7 +71,7 @@ public class SymmetricCrypto {
* 构造
*
* @param algorithm 算法 {@link SymmetricAlgorithm}
* @param key 自定义KEY
* @param key 自定义KEY
*/
public SymmetricCrypto(SymmetricAlgorithm algorithm, byte[] key) {
this(algorithm.getValue(), key);
@@ -73,7 +81,7 @@ public class SymmetricCrypto {
* 构造
*
* @param algorithm 算法 {@link SymmetricAlgorithm}
* @param key 自定义KEY
* @param key 自定义KEY
* @since 3.1.2
*/
public SymmetricCrypto(SymmetricAlgorithm algorithm, SecretKey key) {
@@ -84,7 +92,7 @@ public class SymmetricCrypto {
* 构造
*
* @param algorithm 算法
* @param key 密钥
* @param key 密钥
*/
public SymmetricCrypto(String algorithm, byte[] key) {
this(algorithm, KeyUtil.generateKey(algorithm, key));
@@ -94,7 +102,7 @@ public class SymmetricCrypto {
* 构造
*
* @param algorithm 算法
* @param key 密钥
* @param key 密钥
* @since 3.1.2
*/
public SymmetricCrypto(String algorithm, SecretKey key) {
@@ -104,8 +112,8 @@ public class SymmetricCrypto {
/**
* 构造
*
* @param algorithm 算法
* @param key 密钥
* @param algorithm 算法
* @param key 密钥
* @param paramsSpec 算法参数,例如加盐等
* @since 3.3.0
*/
@@ -117,19 +125,29 @@ public class SymmetricCrypto {
}
// ------------------------------------------------------------------ Constructor end
/**
* 初始化
*
* @param algorithm 算法
* @param key 密钥,如果为<code>null</code>自动生成一个key
* @param key 密钥,如果为<code>null</code>自动生成一个key
* @return {@link SymmetricCrypto}
*/
public SymmetricCrypto init(String algorithm, SecretKey key) {
Assert.notBlank(algorithm, "'algorithm' must be not blank !");
this.secretKey = key;
// 对于PBE算法使用随机数加盐
if (algorithm.startsWith("PBE")) {
// 对于PBE算法使用随机数加盐
this.params = new PBEParameterSpec(RandomUtil.randomBytes(8), 100);
}
// 检查是否为ZeroPadding是则替换为NoPadding并标记以便单独处理
if (algorithm.contains(Padding.ZeroPadding.name())) {
algorithm = StrUtil.replace(algorithm, Padding.ZeroPadding.name(), Padding.NoPadding.name());
this.isZeroPadding = true;
}
this.cipher = SecureUtil.createCipher(algorithm);
return this;
}
@@ -146,6 +164,7 @@ public class SymmetricCrypto {
}
// --------------------------------------------------------------------------------- Encrypt
/**
* 加密
*
@@ -160,7 +179,7 @@ public class SymmetricCrypto {
} else {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, params);
}
return cipher.doFinal(data);
return cipher.doFinal(paddingDataWithZero(data, cipher.getBlockSize()));
} catch (Exception e) {
throw new CryptoException(e);
} finally {
@@ -192,7 +211,7 @@ public class SymmetricCrypto {
/**
* 加密
*
* @param data 被加密的字符串
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的bytes
*/
@@ -203,7 +222,7 @@ public class SymmetricCrypto {
/**
* 加密
*
* @param data 被加密的字符串
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的bytes
*/
@@ -214,7 +233,7 @@ public class SymmetricCrypto {
/**
* 加密
*
* @param data 被加密的字符串
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的Hex
* @since 4.5.12
@@ -226,7 +245,7 @@ public class SymmetricCrypto {
/**
* 加密
*
* @param data 被加密的字符串
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的Hex
* @since 4.5.12
@@ -238,7 +257,7 @@ public class SymmetricCrypto {
/**
* 加密
*
* @param data 被加密的字符串
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的Base64
*/
@@ -249,7 +268,7 @@ public class SymmetricCrypto {
/**
* 加密
*
* @param data 被加密的字符串
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的Base64
* @since 4.5.12
@@ -320,6 +339,7 @@ public class SymmetricCrypto {
}
// --------------------------------------------------------------------------------- Decrypt
/**
* 解密
*
@@ -327,6 +347,9 @@ public class SymmetricCrypto {
* @return 解密后的bytes
*/
public byte[] decrypt(byte[] bytes) {
final int blockSize;
final byte[] decryptData;
lock.lock();
try {
if (null == this.params) {
@@ -334,18 +357,21 @@ public class SymmetricCrypto {
} else {
cipher.init(Cipher.DECRYPT_MODE, secretKey, params);
}
return cipher.doFinal(bytes);
blockSize = cipher.getBlockSize();
decryptData = cipher.doFinal(bytes);
} catch (Exception e) {
throw new CryptoException(e);
} finally {
lock.unlock();
}
return removePadding(decryptData, blockSize);
}
/**
* 解密为字符串
*
* @param bytes 被解密的bytes
* @param bytes 被解密的bytes
* @param charset 解密后的charset
* @return 解密后的String
*/
@@ -376,7 +402,7 @@ public class SymmetricCrypto {
/**
* 解密Hex16进制或Base64表示的字符串
*
* @param data 被解密的String
* @param data 被解密的String
* @param charset 解密后的charset
* @return 解密后的String
*/
@@ -408,7 +434,7 @@ public class SymmetricCrypto {
/**
* 解密,不会关闭流
*
* @param data 被解密的InputStream
* @param data 被解密的InputStream
* @param charset 解密后的charset
* @return 解密后的String
*/
@@ -427,6 +453,7 @@ public class SymmetricCrypto {
}
// --------------------------------------------------------------------------------- Getters
/**
* 获得对称密钥
*
@@ -441,7 +468,64 @@ public class SymmetricCrypto {
*
* @return 加密或解密
*/
public Cipher getClipher() {
public Cipher getCipher() {
return cipher;
}
// --------------------------------------------------------------------------------- Private method start
/**
* 数据按照blockSize的整数倍长度填充填充0
*
* <p>
* 在{@link Padding#ZeroPadding} 模式下且数据长度不是blockSize的整数倍才有效否则返回原数据
*
* <p>
* 见https://blog.csdn.net/OrangeJack/article/details/82913804
*
* @param data 数据
* @param blockSize 块大小
* @return 填充后的数据如果isZeroPadding为false或长度刚好返回原数据
* @since 4.6.7
*/
private byte[] paddingDataWithZero(byte[] data, int blockSize) {
if (this.isZeroPadding) {
final int length = data.length;
// 按照块拆分后的数据中多余的数据
final int remainLength = length % blockSize;
if (remainLength > 0) {
// 新长度为blockSize的整数倍多余部分填充0
return ArrayUtil.resize(data, length + blockSize - remainLength);
}
}
return data;
}
/**
* 数据按照blockSize去除填充部分用于解密
*
* <p>
* 在{@link Padding#ZeroPadding} 模式下且数据长度不是blockSize的整数倍才有效否则返回原数据
*
* @param data 数据
* @param blockSize 块大小
* @return 去除填充后的数据如果isZeroPadding为false或长度刚好返回原数据
* @since 4.6.7
*/
private byte[] removePadding(byte[] data, int blockSize) {
if (this.isZeroPadding) {
final int length = data.length;
final int remainLength = length % blockSize;
if (remainLength == 0) {
// 解码后的数据正好是块大小的整数倍说明可能存在补0的情况去掉末尾所有的0
int i = length - 1;
while (i >= 0 && 0 == data[i]) {
i--;
}
return ArrayUtil.resize(data, i + 1);
}
}
return data;
}
// --------------------------------------------------------------------------------- Private method end
}

View File

@@ -1,5 +1,8 @@
package cn.hutool.crypto.test;
import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.RandomUtil;
import org.junit.Assert;
import org.junit.Test;
@@ -106,6 +109,18 @@ public class SymmetricTest {
Assert.assertEquals("cd0e3a249eaf0ed80c330338508898c4bddcfd665a1b414622164a273ca5daf7b4ebd2c00aaa66b84dd0a237708dac8e", encryptHex);
}
@Test
public void aesZeroPaddingTest() {
String content = RandomUtil.randomString(RandomUtil.randomInt(200));
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, "0123456789ABHAEQ".getBytes(), "DYgjCEIMVrj2W9xN".getBytes());
// 加密为16进制表示
String encryptHex = aes.encryptHex(content);
// 解密
String decryptStr = aes.decryptStr(encryptHex);
Assert.assertEquals(content, decryptStr);
}
@Test
public void desTest() {
String content = "test中文";

View File

@@ -6,10 +6,7 @@ import java.sql.Clob;
import java.sql.RowId;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
@@ -156,7 +153,7 @@ public class Entity extends Dict {
*/
public Entity setFieldNames(Collection<String> fieldNames) {
if (CollectionUtil.isNotEmpty(fieldNames)) {
this.fieldNames = new HashSet<String>(fieldNames);
this.fieldNames = CollectionUtil.newHashSet(true, fieldNames);
}
return this;
}
@@ -169,7 +166,7 @@ public class Entity extends Dict {
*/
public Entity setFieldNames(String... fieldNames) {
if (ArrayUtil.isNotEmpty(fieldNames)) {
this.fieldNames = CollectionUtil.newHashSet(fieldNames);
this.fieldNames = CollectionUtil.newLinkedHashSet(fieldNames);
}
return this;
}
@@ -185,9 +182,7 @@ public class Entity extends Dict {
if (null == this.fieldNames) {
return setFieldNames(fieldNames);
} else {
for (String fieldName : fieldNames) {
this.fieldNames.add(fieldName);
}
Collections.addAll(this.fieldNames, fieldNames);
}
}
return this;