This commit is contained in:
Looly 2023-04-26 13:49:23 +08:00
parent 13d0ce8817
commit c2d419ffdc
10 changed files with 182 additions and 329 deletions

View File

@ -13,6 +13,7 @@
package org.dromara.hutool.crypto; package org.dromara.hutool.crypto;
import org.dromara.hutool.core.exception.ExceptionUtil; import org.dromara.hutool.core.exception.ExceptionUtil;
import org.dromara.hutool.core.exception.HutoolException;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
/** /**
@ -20,30 +21,67 @@ import org.dromara.hutool.core.text.StrUtil;
* @author Looly * @author Looly
* *
*/ */
public class CryptoException extends RuntimeException { public class CryptoException extends HutoolException {
private static final long serialVersionUID = 8068509879445395353L; private static final long serialVersionUID = 8068509879445395353L;
/**
* 构造
*
* @param e 异常
*/
public CryptoException(final Throwable e) { public CryptoException(final Throwable e) {
super(ExceptionUtil.getMessage(e), e); super(e);
} }
/**
* 构造
*
* @param message 消息
*/
public CryptoException(final String message) { public CryptoException(final String message) {
super(message); super(message);
} }
/**
* 构造
*
* @param messageTemplate 消息模板
* @param params 参数
*/
public CryptoException(final String messageTemplate, final Object... params) { public CryptoException(final String messageTemplate, final Object... params) {
super(StrUtil.format(messageTemplate, params)); super(messageTemplate, params);
} }
public CryptoException(final String message, final Throwable throwable) { /**
super(message, throwable); * 构造
*
* @param message 消息
* @param cause 被包装的子异常
*/
public CryptoException(final String message, final Throwable cause) {
super(message, cause);
} }
public CryptoException(final String message, final Throwable throwable, final boolean enableSuppression, final boolean writableStackTrace) { /**
super(message, throwable, enableSuppression, writableStackTrace); * 构造
*
* @param message 消息
* @param cause 被包装的子异常
* @param enableSuppression 是否启用抑制
* @param writableStackTrace 堆栈跟踪是否应该是可写的
*/
public CryptoException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
} }
public CryptoException(final Throwable throwable, final String messageTemplate, final Object... params) { /**
super(StrUtil.format(messageTemplate, params), throwable); * 构造
*
* @param cause 被包装的子异常
* @param messageTemplate 消息模板
* @param params 参数
*/
public CryptoException(final Throwable cause, final String messageTemplate, final Object... params) {
super(cause, messageTemplate, params);
} }
} }

View File

@ -17,6 +17,7 @@ import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.io.IoUtil; import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.array.ArrayUtil; import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.text.CharUtil; import org.dromara.hutool.core.text.CharUtil;
import org.dromara.hutool.core.util.RandomUtil; import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.core.text.StrUtil; import org.dromara.hutool.core.text.StrUtil;
@ -620,7 +621,6 @@ public class KeyUtil {
*/ */
public static KeyGenerator getKeyGenerator(final String algorithm) { public static KeyGenerator getKeyGenerator(final String algorithm) {
final Provider provider = GlobalProviderFactory.getProvider(); final Provider provider = GlobalProviderFactory.getProvider();
final KeyGenerator generator; final KeyGenerator generator;
try { try {
generator = (null == provider) // generator = (null == provider) //

View File

@ -25,14 +25,7 @@ import org.dromara.hutool.crypto.digest.HMac;
import org.dromara.hutool.crypto.digest.HmacAlgorithm; import org.dromara.hutool.crypto.digest.HmacAlgorithm;
import org.dromara.hutool.crypto.digest.MD5; import org.dromara.hutool.crypto.digest.MD5;
import org.dromara.hutool.crypto.provider.GlobalProviderFactory; import org.dromara.hutool.crypto.provider.GlobalProviderFactory;
import org.dromara.hutool.crypto.symmetric.AES; import org.dromara.hutool.crypto.symmetric.*;
import org.dromara.hutool.crypto.symmetric.DES;
import org.dromara.hutool.crypto.symmetric.DESede;
import org.dromara.hutool.crypto.symmetric.PBKDF2;
import org.dromara.hutool.crypto.symmetric.RC4;
import org.dromara.hutool.crypto.symmetric.SymmetricCrypto;
import org.dromara.hutool.crypto.symmetric.ZUC;
import org.dromara.hutool.crypto.symmetric.FPE;
import org.bouncycastle.crypto.AlphabetMapper; import org.bouncycastle.crypto.AlphabetMapper;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -593,10 +586,10 @@ public class SecureUtil {
* RC4算法 * RC4算法
* *
* @param key 密钥 * @param key 密钥
* @return {@link RC4} * @return {@link SymmetricCrypto}
*/ */
public static RC4 rc4(final String key) { public static SymmetricCrypto rc4(final byte[] key) {
return new RC4(key); return new SymmetricCrypto(SymmetricAlgorithm.RC4, key);
} }
/** /**

View File

@ -30,9 +30,9 @@ public class GlobalProviderFactory {
private static final Provider provider = _createProvider(); private static final Provider provider = _createProvider();
/** /**
* 获取{@link Provider} * 获取{@link Provider}无提供方返回{@code null}表示使用JDK默认
* *
* @return {@link Provider} * @return {@link Provider} or {@code null}
*/ */
public static Provider getProvider() { public static Provider getProvider() {
return useCustomProvider ? provider : null; return useCustomProvider ? provider : null;
@ -56,6 +56,7 @@ public class GlobalProviderFactory {
private static Provider _createProvider() { private static Provider _createProvider() {
final ProviderFactory factory = SpiUtil.loadFirstAvailable(ProviderFactory.class); final ProviderFactory factory = SpiUtil.loadFirstAvailable(ProviderFactory.class);
if (null == factory) { if (null == factory) {
// 默认JCE
return null; return null;
} }

View File

@ -1,281 +0,0 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.crypto.symmetric;
import org.dromara.hutool.core.codec.HexUtil;
import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.ByteUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.crypto.CryptoException;
import org.dromara.hutool.crypto.SecureUtil;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
/**
* RC4加密解密算法实现<br>
* 注意由于安全问题已经基本不在HTTPS中使用了<br>
* 来自https://github.com/xSAVIKx/RC4-cipher/blob/master/src/main/java/com/github/xsavikx/rc4/RC4.java
*
* @author Iurii SergiichukLooly
*/
public class RC4 implements Serializable {
private static final long serialVersionUID = 1L;
private static final int SBOX_LENGTH = 256;
/** 密钥最小长度 */
private static final int KEY_MIN_LENGTH = 5;
/** Sbox */
private int[] sbox;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 构造
*
* @param key 密钥
* @throws CryptoException key长度小于5或者大于255抛出此异常
*/
public RC4(final String key) throws CryptoException {
setKey(key);
}
/**
* 加密
*
* @param message 消息
* @param charset 编码
* @return 密文
* @throws CryptoException key长度小于5或者大于255抛出此异常
*/
public byte[] encrypt(final String message, final Charset charset) throws CryptoException {
return crypt(ByteUtil.toBytes(message, charset));
}
/**
* 加密使用默认编码UTF-8
*
* @param message 消息
* @return 密文
* @throws CryptoException key长度小于5或者大于255抛出此异常
*/
public byte[] encrypt(final String message) throws CryptoException {
return encrypt(message, CharsetUtil.UTF_8);
}
/**
* 加密
*
* @param data 数据
* @return 加密后的Hex
* @since 4.5.12
*/
public String encryptHex(final byte[] data) {
return HexUtil.encodeHexStr(crypt(data));
}
/**
* 加密
*
* @param data 数据
* @return 加密后的Base64
* @since 4.5.12
*/
public String encryptBase64(final byte[] data) {
return Base64.encode(crypt(data));
}
/**
* 加密
*
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的Hex
* @since 4.5.12
*/
public String encryptHex(final String data, final Charset charset) {
return HexUtil.encodeHexStr(encrypt(data, charset));
}
/**
* 加密使用UTF-8编码
*
* @param data 被加密的字符串
* @return 加密后的Hex
* @since 5.4.4
*/
public String encryptHex(final String data) {
return HexUtil.encodeHexStr(encrypt(data));
}
/**
* 加密
*
* @param data 被加密的字符串
* @param charset 编码
* @return 加密后的Base64
* @since 4.5.12
*/
public String encryptBase64(final String data, final Charset charset) {
return Base64.encode(encrypt(data, charset));
}
/**
* 加密使用UTF-8编码
*
* @param data 被加密的字符串
* @return 加密后的Base64
* @since 5.4.4
*/
public String encryptBase64(final String data) {
return Base64.encode(encrypt(data));
}
/**
* 解密
*
* @param message 消息
* @param charset 编码
* @return 明文
* @throws CryptoException key长度小于5或者大于255抛出此异常
*/
public String decrypt(final byte[] message, final Charset charset) throws CryptoException {
return StrUtil.str(crypt(message), charset);
}
/**
* 解密使用默认编码UTF-8
*
* @param message 消息
* @return 明文
* @throws CryptoException key长度小于5或者大于255抛出此异常
*/
public String decrypt(final byte[] message) throws CryptoException {
return decrypt(message, CharsetUtil.UTF_8);
}
/**
* 解密Hex16进制或Base64表示的字符串使用默认编码UTF-8
*
* @param message 消息
* @return 明文
* @since 5.4.4
*/
public String decrypt(final String message) {
return decrypt(SecureUtil.decode(message));
}
/**
* 解密Hex16进制或Base64表示的字符串
*
* @param message 明文
* @param charset 解密后的charset
* @return 明文
* @since 5.4.4
*/
public String decrypt(final String message, final Charset charset) {
return StrUtil.str(decrypt(message), charset);
}
/**
* 加密或解密指定值调用此方法前需初始化密钥
*
* @param msg 要加密或解密的消息
* @return 加密或解密后的值
*/
public byte[] crypt(final byte[] msg) {
final ReadLock readLock = this.lock.readLock();
byte[] code;
readLock.lock();
try {
final int[] sbox = this.sbox.clone();
code = new byte[msg.length];
int i = 0;
int j = 0;
for (int n = 0; n < msg.length; n++) {
i = (i + 1) % SBOX_LENGTH;
j = (j + sbox[i]) % SBOX_LENGTH;
swap(i, j, sbox);
final int rand = sbox[(sbox[i] + sbox[j]) % SBOX_LENGTH];
code[n] = (byte) (rand ^ msg[n]);
}
} finally {
readLock.unlock();
}
return code;
}
/**
* 设置密钥
*
* @param key 密钥
* @throws CryptoException key长度小于5或者大于255抛出此异常
*/
public void setKey(final String key) throws CryptoException {
final int length = key.length();
if (length < KEY_MIN_LENGTH || length >= SBOX_LENGTH) {
throw new CryptoException("Key length has to be between {} and {}", KEY_MIN_LENGTH, (SBOX_LENGTH - 1));
}
final WriteLock writeLock = this.lock.writeLock();
writeLock.lock();
try {
this.sbox = initSBox(ByteUtil.toUtf8Bytes(key));
} finally {
writeLock.unlock();
}
}
//----------------------------------------------------------------------------------------------------------------------- Private method start
/**
* 初始化Sbox
*
* @param key 密钥
* @return sbox
*/
private int[] initSBox(final byte[] key) {
final int[] sbox = new int[SBOX_LENGTH];
int j = 0;
for (int i = 0; i < SBOX_LENGTH; i++) {
sbox[i] = i;
}
for (int i = 0; i < SBOX_LENGTH; i++) {
j = (j + sbox[i] + (key[i % key.length]) & 0xFF) % SBOX_LENGTH;
swap(i, j, sbox);
}
return sbox;
}
/**
* 交换指定两个位置的值
*
* @param i 位置1
* @param j 位置2
* @param sbox 数组
*/
private void swap(final int i, final int j, final int[] sbox) {
final int temp = sbox[i];
sbox[i] = sbox[j];
sbox[j] = temp;
}
//----------------------------------------------------------------------------------------------------------------------- Private method end
}

View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.dromara.hutool.crypto.symmetric;
import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.crypto.digest.DigestUtil;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
/**
* OpenSSL风格前缀和加盐相关工具类<br>
* 参考https://stackoverflow.com/questions/32508961/java-equivalent-of-an-openssl-aes-cbc-encryption
*
* @author looly
* @since 6.0.0
*/
public class SaltUtil {
private final static byte SALT_LEN = 8;
private final static byte IV_LEN = 16;
private final static byte KEY_LEN = 32;
/**
* OpenSSL's magic initial bytes.
*/
private static final byte[] SALTED_MAGIC = "Salted__".getBytes(StandardCharsets.US_ASCII);
/**
* 获取8位salt随机数<br>
*
* @param encryptedData 密文
* @return salt随机数
*/
public static byte[] getSalt(final byte[] encryptedData) {
if (ArrayUtil.startWith(encryptedData, SALTED_MAGIC)) {
return Arrays.copyOfRange(encryptedData, SALTED_MAGIC.length, SALTED_MAGIC.length + SALT_LEN);
}
return null;
}
/**
* 通过密钥和salt值获取实际的密钥
*
* @param pass 密钥
* @param salt 加盐值
* @return 实际密钥
*/
public static byte[] getKey(final byte[] pass, final byte[] salt) {
if (null == salt) {
return pass;
}
final byte[] passAndSalt = arrayConcat(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = arrayConcat(hash, passAndSalt);
hash = DigestUtil.md5(hashData);
keyAndIv = arrayConcat(keyAndIv, hash);
}
return Arrays.copyOfRange(keyAndIv, 0, KEY_LEN);
}
private static byte[] arrayConcat(final byte[] a, final byte[] b) {
if (ArrayUtil.isEmpty(a)) {
return b;
}
final byte[] c = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
}

View File

@ -43,6 +43,10 @@ public enum SymmetricAlgorithm {
* RC2 * RC2
*/ */
RC2("RC2"), RC2("RC2"),
/**
* RC4
*/
RC4("RC4"),
/** /**
*PBEWithMD5AndDES *PBEWithMD5AndDES
*/ */

View File

@ -219,7 +219,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return this * @return this
* @since 5.7.17 * @since 5.7.17
*/ */
public SymmetricCrypto setRandom(final SecureRandom random){ public SymmetricCrypto setRandom(final SecureRandom random) {
this.cipherWrapper.setRandom(random); this.cipherWrapper.setRandom(random);
return this; return this;
} }
@ -233,7 +233,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return this * @return this
* @since 5.7.12 * @since 5.7.12
*/ */
public SymmetricCrypto setMode(final CipherMode mode){ public SymmetricCrypto setMode(final CipherMode mode) {
lock.lock(); lock.lock();
try { try {
initMode(mode.getValue()); initMode(mode.getValue());
@ -335,6 +335,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
final byte[] decryptData; final byte[] decryptData;
lock.lock(); lock.lock();
try { try {
final Cipher cipher = initMode(Cipher.DECRYPT_MODE); final Cipher cipher = initMode(Cipher.DECRYPT_MODE);
blockSize = cipher.getBlockSize(); blockSize = cipher.getBlockSize();

View File

@ -2,6 +2,7 @@ package org.dromara.hutool.crypto.symmetric;
import org.dromara.hutool.core.codec.binary.Base64; import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.codec.HexUtil; import org.dromara.hutool.core.codec.HexUtil;
import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.util.RandomUtil; import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.crypto.KeyUtil; import org.dromara.hutool.crypto.KeyUtil;
import org.dromara.hutool.crypto.Mode; import org.dromara.hutool.crypto.Mode;

View File

@ -1,38 +1,41 @@
package org.dromara.hutool.crypto.symmetric; package org.dromara.hutool.crypto.symmetric;
import org.dromara.hutool.core.util.CharsetUtil; import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.crypto.provider.GlobalProviderFactory;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.nio.charset.StandardCharsets;
public class RC4Test { public class RC4Test {
@Test @Test
public void testCryptMessage() { public void testCryptMessage() {
final String key = "This is pretty long key"; final byte[] key = "This is pretty long key".getBytes();
final RC4 rc4 = new RC4(key); final SymmetricCrypto SymmetricCrypto = new SymmetricCrypto("RC4", key);
final String message = "Hello, World!"; final String message = "Hello, World!";
final byte[] crypt = rc4.encrypt(message); final byte[] crypt = SymmetricCrypto.encrypt(message);
final String msg = rc4.decrypt(crypt); final String msg = SymmetricCrypto.decryptStr(crypt);
Assertions.assertEquals(message, msg); Assertions.assertEquals(message, msg);
final String message2 = "Hello, World this is megssage 2"; final String message2 = "Hello, World this is megssage 2";
final byte[] crypt2 = rc4.encrypt(message2); final byte[] crypt2 = SymmetricCrypto.encrypt(message2);
final String msg2 = rc4.decrypt(crypt2); final String msg2 = SymmetricCrypto.decryptStr(crypt2);
Assertions.assertEquals(message2, msg2); Assertions.assertEquals(message2, msg2);
} }
@Test @Test
public void testCryptWithChineseCharacters() { public void testCryptWithChineseCharacters() {
final String message = "这是一个中文消息!"; final String message = "这是一个中文消息!";
final String key = "我是一个文件密钥"; final byte[] key = "我是一个文件密钥".getBytes(StandardCharsets.UTF_8);
final RC4 rc4 = new RC4(key); final SymmetricCrypto SymmetricCrypto = new SymmetricCrypto("RC4", key);
final byte[] crypt = rc4.encrypt(message); final byte[] crypt = SymmetricCrypto.encrypt(message);
final String msg = rc4.decrypt(crypt); final String msg = SymmetricCrypto.decryptStr(crypt);
Assertions.assertEquals(message, msg); Assertions.assertEquals(message, msg);
final String message2 = "这是第二个中文消息!"; final String message2 = "这是第二个中文消息!";
final byte[] crypt2 = rc4.encrypt(message2); final byte[] crypt2 = SymmetricCrypto.encrypt(message2);
final String msg2 = rc4.decrypt(crypt2); final String msg2 = SymmetricCrypto.decryptStr(crypt2);
Assertions.assertEquals(message2, msg2); Assertions.assertEquals(message2, msg2);
} }
@ -40,14 +43,14 @@ public class RC4Test {
public void testDecryptWithHexMessage() { public void testDecryptWithHexMessage() {
final String message = "这是第一个用来测试密文为十六进制字符串的消息!"; final String message = "这是第一个用来测试密文为十六进制字符串的消息!";
final String key = "生成一个密钥"; final String key = "生成一个密钥";
final RC4 rc4 = new RC4(key); final SymmetricCrypto SymmetricCrypto = new SymmetricCrypto("RC4", key.getBytes(StandardCharsets.UTF_8));
final String encryptHex = rc4.encryptHex(message, CharsetUtil.UTF_8); final String encryptHex = SymmetricCrypto.encryptHex(message, CharsetUtil.UTF_8);
final String msg = rc4.decrypt(encryptHex); final String msg = SymmetricCrypto.decryptStr(encryptHex);
Assertions.assertEquals(message, msg); Assertions.assertEquals(message, msg);
final String message2 = "这是第二个用来测试密文为十六进制字符串的消息!"; final String message2 = "这是第二个用来测试密文为十六进制字符串的消息!";
final String encryptHex2 = rc4.encryptHex(message2); final String encryptHex2 = SymmetricCrypto.encryptHex(message2);
final String msg2 = rc4.decrypt(encryptHex2); final String msg2 = SymmetricCrypto.decryptStr(encryptHex2);
Assertions.assertEquals(message2, msg2); Assertions.assertEquals(message2, msg2);
} }
@ -56,14 +59,21 @@ public class RC4Test {
public void testDecryptWithBase64Message() { public void testDecryptWithBase64Message() {
final String message = "这是第一个用来测试密文为Base64编码的消息"; final String message = "这是第一个用来测试密文为Base64编码的消息";
final String key = "生成一个密钥"; final String key = "生成一个密钥";
final RC4 rc4 = new RC4(key); final SymmetricCrypto SymmetricCrypto = new SymmetricCrypto("RC4", key.getBytes(StandardCharsets.UTF_8));
final String encryptHex = rc4.encryptBase64(message, CharsetUtil.UTF_8); final String encryptHex = SymmetricCrypto.encryptBase64(message, CharsetUtil.UTF_8);
final String msg = rc4.decrypt(encryptHex); final String msg = SymmetricCrypto.decryptStr(encryptHex);
Assertions.assertEquals(message, msg); Assertions.assertEquals(message, msg);
final String message2 = "这是第一个用来测试密文为Base64编码的消息"; final String message2 = "这是第一个用来测试密文为Base64编码的消息";
final String encryptHex2 = rc4.encryptBase64(message2); final String encryptHex2 = SymmetricCrypto.encryptBase64(message2);
final String msg2 = rc4.decrypt(encryptHex2); final String msg2 = SymmetricCrypto.decryptStr(encryptHex2);
Assertions.assertEquals(message2, msg2); Assertions.assertEquals(message2, msg2);
} }
@Test
void decryptTest() {
GlobalProviderFactory.setUseCustomProvider(false);
final String key16 = "1234567890123456";
final SymmetricCrypto aes = new SymmetricCrypto("SymmetricCrypto", key16.getBytes());
}
} }