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 a88795ac8..6709cfb84 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
@@ -12,6 +12,10 @@
package org.dromara.hutool.crypto;
+import org.bouncycastle.crypto.BufferedBlockCipher;
+
+import java.util.Arrays;
+
/**
* 密码接口,提供统一的API,用于兼容和统一JCE和BouncyCastle等库的操作
*
@@ -30,7 +34,7 @@ public interface Cipher {
/**
* 获取块大小,当为Stream方式加密时返回0
*
- * @return 块大小
+ * @return 块大小,-1表示非块加密
*/
int getBlockSize();
@@ -42,16 +46,59 @@ public interface Cipher {
*/
void init(CipherMode mode, Parameters parameters);
+ /**
+ * 根据输入长度,获取输出长度,输出长度与算法相关
+ * 输出长度只针对本次输入关联,即len长度的数据对应输出长度加doFinal的长度
+ *
+ * @param len 输入长度
+ * @return 输出长度,-1表示非块加密
+ */
+ int getOutputSize(int len);
+
/**
* 执行运算,可以是加密运算或解密运算
*
- * @param data 被处理的数据
- * @return 运算结果
+ * @param in 输入数据
+ * @param inOff 输入数据开始位置
+ * @param len 被处理数据长度
+ * @param out 输出数据
+ * @param outOff 输出数据开始位置
+ * @return 处理长度
*/
- byte[] process(byte[] data);
+ int process(byte[] in, int inOff, int len, byte[] out, int outOff);
+
+ /**
+ * 处理最后一块数据
+ * 当{@link #process(byte[], int, int, byte[], int)}处理完数据后非完整块数据,此方法用于处理块中剩余的bytes
+ * 如加密数据要求128bit,即16byes的整数,单数处理数据后为15bytes,此时根据padding方式不同,可填充剩余1byte为指定值(如填充0)
+ * 当对数据进行分段加密时,需要首先多次执行process方法,在最后一块数据处理完后执行此方法。
+ *
+ * @param out 经过process执行过运算的结果数据
+ * @param outOff 数据处理开始位置
+ * @return 处理长度
+ */
+ int doFinal(byte[] out, int outOff);
+
+ /**
+ * 处理数据,并返回最终结果
+ *
+ * @param in 输入数据
+ * @return 结果数据
+ */
+ default byte[] processFinal(final byte[] in) {
+ final byte[] buf = new byte[getOutputSize(in.length)];
+ int len = process(in, 0, in.length, buf, 0);
+ len += doFinal(buf, len);
+
+ if (len == buf.length) {
+ return buf;
+ }
+ return Arrays.copyOfRange(buf, 0, len);
+ }
/**
* Cipher所需参数,包括Key、Random、IV等信息
*/
- interface Parameters { }
+ interface Parameters {
+ }
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java
index c94eb2336..4e2317261 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CipherMode.java
@@ -24,19 +24,19 @@ public enum CipherMode {
/**
* 加密模式
*/
- encrypt(Cipher.ENCRYPT_MODE),
+ ENCRYPT(Cipher.ENCRYPT_MODE),
/**
* 解密模式
*/
- decrypt(Cipher.DECRYPT_MODE),
+ DECRYPT(Cipher.DECRYPT_MODE),
/**
* 包装模式
*/
- wrap(Cipher.WRAP_MODE),
+ WRAP(Cipher.WRAP_MODE),
/**
* 拆包模式
*/
- unwrap(Cipher.UNWRAP_MODE);
+ UNWRAP(Cipher.UNWRAP_MODE);
/**
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 85d70ac3e..d4dbd5c07 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
@@ -15,6 +15,7 @@ package org.dromara.hutool.crypto;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.wrapper.Wrapper;
+import javax.crypto.ShortBufferException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -63,6 +64,11 @@ public class JceCipher implements Cipher, Wrapper {
return this.cipher.getBlockSize();
}
+ @Override
+ public int getOutputSize(final int len) {
+ return this.cipher.getOutputSize(len);
+ }
+
@Override
public void init(final CipherMode mode, final Parameters parameters) {
Assert.isInstanceOf(JceParameters.class, parameters, "Only support JceParameters!");
@@ -100,8 +106,30 @@ public class JceCipher implements Cipher, Wrapper {
}
@Override
- public byte[] process(final byte[] data) {
- return new byte[0];
+ public int process(final byte[] in, final int inOff, final int len, final byte[] out, final int outOff) {
+ try {
+ return this.cipher.update(in, inOff, len, out, outOff);
+ } catch (final ShortBufferException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ @Override
+ public int doFinal(final byte[] out, final int outOff) {
+ try {
+ return this.cipher.doFinal(out, outOff);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ @Override
+ public byte[] processFinal(final byte[] data) {
+ try {
+ return this.cipher.doFinal(data);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
}
/**
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
index 1731a0b62..5542d8395 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/asymmetric/AsymmetricCrypto.java
@@ -21,8 +21,6 @@ import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
@@ -149,8 +147,8 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
*/
public AsymmetricCrypto(final String algorithm, final byte[] privateKey, final byte[] publicKey) {
this(algorithm, //
- KeyUtil.generatePrivateKey(algorithm, privateKey), //
- KeyUtil.generatePublicKey(algorithm, publicKey)//
+ KeyUtil.generatePrivateKey(algorithm, privateKey), //
+ KeyUtil.generatePublicKey(algorithm, publicKey)//
);
}
@@ -255,7 +253,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
final Key key = getKeyByType(keyType);
lock.lock();
try {
- final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, key);
+ final JceCipher cipher = initMode(CipherMode.ENCRYPT, key);
if (this.encryptBlockSize < 0) {
// 在引入BC库情况下,自动获取块大小
@@ -280,7 +278,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
final Key key = getKeyByType(keyType);
lock.lock();
try {
- final Cipher cipher = initMode(Cipher.DECRYPT_MODE, key);
+ final JceCipher cipher = initMode(CipherMode.DECRYPT, key);
if (this.decryptBlockSize < 0) {
// 在引入BC库情况下,自动获取块大小
@@ -352,9 +350,10 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
* @throws BadPaddingException padding错误异常
* @throws IOException IO异常,不会被触发
*/
+ @SuppressWarnings("resource")
private byte[] doFinalWithBlock(final byte[] data, final int maxBlockSize) throws IllegalBlockSizeException, BadPaddingException, IOException {
final int dataLength = data.length;
- @SuppressWarnings("resource") final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
+ final FastByteArrayOutputStream out = new FastByteArrayOutputStream();
int offSet = 0;
// 剩余长度
@@ -373,18 +372,15 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto
}
/**
- * 初始化{@link Cipher}的模式,如加密模式或解密模式
+ * 初始化{@link JceCipher}的模式,如加密模式或解密模式
*
- * @param mode 模式,可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE}
+ * @param mode 模式,可选{@link CipherMode#ENCRYPT}或者{@link CipherMode#DECRYPT}
* @param key 密钥
- * @return {@link Cipher}
- * @throws InvalidAlgorithmParameterException 异常算法错误
- * @throws InvalidKeyException 异常KEY错误
+ * @return {@link JceCipher}
*/
- private Cipher initMode(final int mode, final Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
+ private JceCipher initMode(final CipherMode mode, final Key key) {
final JceCipher cipher = this.cipher;
- cipher.init(mode,
- new JceCipher.JceParameters(key, this.algorithmParameterSpec, this.random));
- return cipher.getRaw();
+ cipher.init(mode, new JceCipher.JceParameters(key, this.algorithmParameterSpec, this.random));
+ return cipher;
}
}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
index 34a05db0b..44f4eccfd 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/bc/BCCipher.java
@@ -14,6 +14,9 @@ package org.dromara.hutool.crypto.bc;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherParameters;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.StreamCipher;
+import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.lang.wrapper.Wrapper;
import org.dromara.hutool.crypto.Cipher;
@@ -21,16 +24,31 @@ import org.dromara.hutool.crypto.CipherMode;
import org.dromara.hutool.crypto.CryptoException;
/**
- * 基于BouncyCastle库的{@link BufferedBlockCipher}封装的加密解密实现
+ * 基于BouncyCastle库封装的加密解密实现,包装包括:
+ *
+ * - {@link BufferedBlockCipher}
+ * - {@link StreamCipher}
+ * - {@link AEADBlockCipher}
+ *
*
* @author Looly, changhr2013
*/
-public class BCCipher implements Cipher, Wrapper {
+public class BCCipher implements Cipher, Wrapper