diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
index a131ab464..f3167f3a5 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/Cipher.java
@@ -49,8 +49,9 @@ public interface Cipher {
void init(CipherMode mode, Parameters parameters);
/**
- * 根据输入长度,获取输出长度,输出长度与算法相关
- * 输出长度只针对本次输入关联,即len长度的数据对应输出长度加doFinal的长度
+ * 返回输出缓冲区为了保存下一个update或doFinal操作的结果所需的长度(以字节为单位)
+ * 下一个update或doFinal调用的实际输出长度可能小于此方法返回的长度。
+ * 一般为块大小对应的输出大小
*
* @param len 输入长度
* @return 输出长度,-1表示非块加密
@@ -58,7 +59,8 @@ public interface Cipher {
int getOutputSize(int len);
/**
- * 执行运算,可以是加密运算或解密运算
+ * 执行运算,可以是加密运算或解密运算
+ * 此方法主要处理一块数据,一块数据处理完毕后,应调用{@link #doFinal(byte[], int)}处理padding等剩余数据。
*
* @param in 输入数据
* @param inOff 输入数据开始位置
@@ -82,7 +84,8 @@ public interface Cipher {
int doFinal(byte[] out, int outOff);
/**
- * 处理数据,并返回最终结果
+ * 处理数据,并返回最终结果
+ * 此方法用于完整处理一块数据并返回。
*
* @param in 输入数据
* @return 结果数据
@@ -92,12 +95,15 @@ public interface Cipher {
}
/**
- * 处理数据,并返回最终结果
+ * 处理数据,并返回最终结果
+ * 此方法用于完整处理一块数据并返回。
*
- * @param in 输入数据
+ * @param in 输入数据
* @param inOffset 输入开始的 input中的偏移量
* @param inputLen 输入长度
* @return 结果数据
+ * @see #process(byte[], int, int, byte[], int)
+ * @see #doFinal(byte[], int)
*/
default byte[] processFinal(final byte[] in, final int inOffset, final int inputLen) {
final byte[] buf = new byte[getOutputSize(in.length)];
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
index da4326be5..c2514dcc8 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/JceCipher.java
@@ -66,6 +66,16 @@ public class JceCipher extends SimpleWrapper implements Cip
return this.raw.getOutputSize(len);
}
+ /**
+ * 返回新缓冲区中的初始化向量(IV)
+ * 这在创建随机IV的情况下,或在基于密码的加密或解密的上下文中是有用的,其中IV是从用户提供的密码导出的。
+ *
+ * @return 新缓冲区中的初始化向量,如果基础算法不使用IV,或者尚未设置IV,则为null。
+ */
+ public byte[] getIV() {
+ return this.raw.getIV();
+ }
+
@Override
public void init(final CipherMode mode, final Parameters parameters) {
Assert.isInstanceOf(JceParameters.class, parameters, "Only support JceParameters!");
@@ -120,6 +130,15 @@ public class JceCipher extends SimpleWrapper implements Cip
}
}
+ @Override
+ public byte[] processFinal(final byte[] in) {
+ try {
+ return this.raw.doFinal(in);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
+ }
+
@Override
public byte[] processFinal(final byte[] data, final int inOffset, final int inputLen) {
try {
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java
index 34f07103d..dadd839da 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/symmetric/SymmetricCrypto.java
@@ -294,6 +294,32 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
return HexUtil.encodeStr(update(data));
}
+ /**
+ * 完成多部分加密或解密操作,具体取决于此密码的初始化方式。
+ *
+ * @return 带有结果的新缓冲区
+ */
+ public byte[] doFinal() {
+ final Cipher cipher = this.cipher.getRaw();
+ lock.lock();
+ try {
+ return cipher.doFinal();
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * 完成多部分加密或解密操作,具体取决于此密码的初始化方式。
+ *
+ * @return 带有结果的新缓冲区
+ */
+ public String doFinalHex() {
+ return HexUtil.encodeStr(doFinal());
+ }
+
// --------------------------------------------------------------------------------- Encrypt
@Override
diff --git a/hutool-crypto/src/test/java/org/dromara/hutool/crypto/symmetric/SymmetricTest.java b/hutool-crypto/src/test/java/org/dromara/hutool/crypto/symmetric/SymmetricTest.java
index 355840ecd..e5613ff73 100644
--- a/hutool-crypto/src/test/java/org/dromara/hutool/crypto/symmetric/SymmetricTest.java
+++ b/hutool-crypto/src/test/java/org/dromara/hutool/crypto/symmetric/SymmetricTest.java
@@ -13,20 +13,17 @@
package org.dromara.hutool.crypto.symmetric;
import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.core.util.CharsetUtil;
import org.dromara.hutool.core.util.RandomUtil;
-import org.dromara.hutool.core.text.StrUtil;
-import org.dromara.hutool.crypto.CipherMode;
-import org.dromara.hutool.crypto.KeyUtil;
-import org.dromara.hutool.crypto.Mode;
-import org.dromara.hutool.crypto.Padding;
-import org.dromara.hutool.crypto.SecureUtil;
-import org.junit.jupiter.api.Assertions;
+import org.dromara.hutool.crypto.*;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
/**
* 对称加密算法单元测试
*
@@ -49,14 +46,14 @@ public class SymmetricTest {
// 解密
final byte[] decrypt = aes.decrypt(encrypt);
- Assertions.assertEquals(content, StrUtil.str(decrypt, CharsetUtil.UTF_8));
+ assertEquals(content, StrUtil.str(decrypt, CharsetUtil.UTF_8));
// 加密为16进制表示
final String encryptHex = aes.encryptHex(content);
// 解密为字符串
final String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.UTF_8);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -74,14 +71,14 @@ public class SymmetricTest {
// 解密
final byte[] decrypt = aes.decrypt(encrypt);
- Assertions.assertEquals(content, StrUtil.utf8Str(decrypt));
+ assertEquals(content, StrUtil.utf8Str(decrypt));
// 加密为16进制表示
final String encryptHex = aes.encryptHex(content);
// 解密为字符串
final String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.UTF_8);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -95,14 +92,14 @@ public class SymmetricTest {
// 解密
final byte[] decrypt = aes.decrypt(encrypt);
- Assertions.assertEquals(content, StrUtil.utf8Str(decrypt));
+ assertEquals(content, StrUtil.utf8Str(decrypt));
// 加密为16进制表示
final String encryptHex = aes.encryptHex(content);
// 解密为字符串
final String decryptStr = aes.decryptStr(encryptHex, CharsetUtil.UTF_8);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -113,20 +110,20 @@ public class SymmetricTest {
// 加密为16进制表示
final String encryptHex = aes.encryptHex(content);
- Assertions.assertEquals("cd0e3a249eaf0ed80c330338508898c4bddcfd665a1b414622164a273ca5daf7b4ebd2c00aaa66b84dd0a237708dac8e", encryptHex);
+ assertEquals("cd0e3a249eaf0ed80c330338508898c4bddcfd665a1b414622164a273ca5daf7b4ebd2c00aaa66b84dd0a237708dac8e", encryptHex);
}
@Test
public void pbeWithoutIvTest() {
final String content = "4321c9a2db2e6b08987c3b903d8d11ff";
final SymmetricCrypto crypto = new SymmetricCrypto(SymmetricAlgorithm.PBEWithMD5AndDES,
- "0123456789ABHAEQ".getBytes());
+ "0123456789ABHAEQ".getBytes());
// 加密为16进制表示
final String encryptHex = crypto.encryptHex(content);
final String data = crypto.decryptStr(encryptHex);
- Assertions.assertEquals(content, data);
+ assertEquals(content, data);
}
@Test
@@ -136,11 +133,16 @@ public class SymmetricTest {
// 加密为16进制表示
aes.setMode(CipherMode.ENCRYPT);
- final String randomData = aes.updateHex(content.getBytes(StandardCharsets.UTF_8));
- aes.setMode(CipherMode.ENCRYPT);
- final String randomData2 = aes.updateHex(content.getBytes(StandardCharsets.UTF_8));
- Assertions.assertEquals(randomData2, randomData);
- Assertions.assertEquals(randomData, "cd0e3a249eaf0ed80c330338508898c4");
+ final String randomData = aes.encryptHex(content.getBytes(StandardCharsets.UTF_8));
+ assertEquals("cd0e3a249eaf0ed80c330338508898c4bddcfd665a1b414622164a273ca5daf7b4ebd2c00aaa66b84dd0a237708dac8e", randomData);
+
+ /// 分段加密,update时只是生成部分密文
+ String randomData2 = aes.updateHex(content.getBytes(StandardCharsets.UTF_8));
+ assertEquals("cd0e3a249eaf0ed80c330338508898c4", randomData2);
+
+ // doFinal后生成剩余内容
+ randomData2 += aes.doFinalHex();
+ assertEquals(randomData, randomData2);
}
@@ -153,7 +155,7 @@ public class SymmetricTest {
final String encryptHex = aes.encryptHex(content);
// 解密
final String decryptStr = aes.decryptStr(encryptHex);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -167,21 +169,21 @@ public class SymmetricTest {
final ByteArrayOutputStream contentStream = new ByteArrayOutputStream();
aes.decrypt(IoUtil.toStream(encryptStream), contentStream, true);
- Assertions.assertEquals(content, StrUtil.utf8Str(contentStream.toByteArray()));
+ assertEquals(content, StrUtil.utf8Str(contentStream.toByteArray()));
}
@Test
public void aesPkcs7PaddingTest() {
final String content = RandomUtil.randomStringLower(RandomUtil.randomInt(200));
final AES aes = new AES("CBC", "PKCS7Padding",
- RandomUtil.randomBytes(32),
- "DYgjCEIMVrj2W9xN".getBytes());
+ RandomUtil.randomBytes(32),
+ "DYgjCEIMVrj2W9xN".getBytes());
// 加密为16进制表示
final String encryptHex = aes.encryptHex(content);
// 解密
final String decryptStr = aes.decryptStr(encryptHex);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -195,12 +197,12 @@ public class SymmetricTest {
final byte[] encrypt = des.encrypt(content);
final byte[] decrypt = des.decrypt(encrypt);
- Assertions.assertEquals(content, StrUtil.utf8Str(decrypt));
+ assertEquals(content, StrUtil.utf8Str(decrypt));
final String encryptHex = des.encryptHex(content);
final String decryptStr = des.decryptStr(encryptHex);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -214,12 +216,12 @@ public class SymmetricTest {
final byte[] encrypt = des.encrypt(content);
final byte[] decrypt = des.decrypt(encrypt);
- Assertions.assertEquals(content, StrUtil.utf8Str(decrypt));
+ assertEquals(content, StrUtil.utf8Str(decrypt));
final String encryptHex = des.encryptHex(content);
final String decryptStr = des.decryptStr(encryptHex);
- Assertions.assertEquals(content, decryptStr);
+ assertEquals(content, decryptStr);
}
@Test
@@ -228,8 +230,8 @@ public class SymmetricTest {
final String key = "CompleteVictory";
final String encrypt = Vigenere.encrypt(content, key);
- Assertions.assertEquals("zXScRZ]KIOMhQjc0\\bYRXZOJK[Vi", encrypt);
+ assertEquals("zXScRZ]KIOMhQjc0\\bYRXZOJK[Vi", encrypt);
final String decrypt = Vigenere.decrypt(encrypt, key);
- Assertions.assertEquals(content, decrypt);
+ assertEquals(content, decrypt);
}
}