add CipherWrapper

This commit is contained in:
Looly 2021-11-19 01:30:08 +08:00
parent 6ed8588c83
commit 851a10d3b0
4 changed files with 174 additions and 50 deletions

View File

@ -19,6 +19,7 @@
* 【core 】 增加DefaultCloneablepr#459@Gitee
* 【core 】 CollStreamUtil增加是否并行的重载pr#467@Gitee
* 【core 】 ResourceClassLoader增加缓存pr#1959@Github
* 【crypto 】 增加CipherWrapper增加setRandompr#1959@Github
*
### 🐞Bug修复
* 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github

View File

@ -0,0 +1,121 @@
package cn.hutool.crypto;
import javax.crypto.Cipher;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
/**
* {@link Cipher}包装类提供初始化模式等额外方法<br>
* 包装之后可提供自定义或默认的
* <ul>
* <li>{@link AlgorithmParameterSpec}</li>
* <li>{@link SecureRandom}</li>
* </ul>
*
* @author looly
* @since 5.7.17
*/
public class CipherWrapper {
private final Cipher cipher;
/**
* 算法参数
*/
private AlgorithmParameterSpec params;
/**
* 随机数生成器可自定义随机数种子
*/
private SecureRandom random;
/**
* 构造
*
* @param algorithm 算法名称
*/
public CipherWrapper(String algorithm) {
this(SecureUtil.createCipher(algorithm));
}
/**
* 构造
*
* @param cipher {@link Cipher}
*/
public CipherWrapper(Cipher cipher) {
this.cipher = cipher;
}
/**
* 获取{@link AlgorithmParameterSpec}<br>
* 在某些算法中需要特别的参数例如在ECIES中此处为IESParameterSpec
*
* @return {@link AlgorithmParameterSpec}
*/
public AlgorithmParameterSpec getParams() {
return this.params;
}
/**
* 设置 {@link AlgorithmParameterSpec}通常用于加盐或偏移向量
*
* @param params {@link AlgorithmParameterSpec}
* @return this
*/
public CipherWrapper setParams(AlgorithmParameterSpec params) {
this.params = params;
return this;
}
/**
* 设置随机数生成器可自定义随机数种子
*
* @param random 随机数生成器可自定义随机数种子
* @return this
*/
public CipherWrapper setRandom(SecureRandom random) {
this.random = random;
return this;
}
/**
* 获取被包装的{@link Cipher}
*
* @return {@link Cipher}
*/
public Cipher getCipher() {
return this.cipher;
}
/**
* 初始化{@link Cipher}为加密或者解密模式
*
* @param mode 模式{@link Cipher#ENCRYPT_MODE} {@link Cipher#DECRYPT_MODE}
* @param key 密钥
* @return this
* @throws InvalidKeyException 无效key
* @throws InvalidAlgorithmParameterException 无效算法
*/
public CipherWrapper initMode(int mode, Key key)
throws InvalidKeyException, InvalidAlgorithmParameterException {
final Cipher cipher = this.cipher;
final AlgorithmParameterSpec params = this.params;
final SecureRandom random = this.random;
if (null != params) {
if (null != random) {
cipher.init(mode, key, params, random);
} else {
cipher.init(mode, key, params);
}
} else {
if (null != random) {
cipher.init(mode, key, random);
} else {
cipher.init(mode, key);
}
}
return this;
}
}

View File

@ -2,6 +2,7 @@ package cn.hutool.crypto.asymmetric;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.crypto.CipherWrapper;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
@ -16,6 +17,7 @@ import java.security.InvalidKeyException;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
/**
@ -37,7 +39,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
/**
* Cipher负责完成加密或解密工作
*/
protected Cipher cipher;
protected CipherWrapper cipherWrapper;
/**
* 加密的块大小
@ -47,12 +49,6 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* 解密的块大小
*/
protected int decryptBlockSize = -1;
/**
* 算法参数
*/
private AlgorithmParameterSpec algorithmParameterSpec;
// ------------------------------------------------------------------ Constructor start
/**
@ -201,7 +197,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 5.4.3
*/
public AlgorithmParameterSpec getAlgorithmParameterSpec() {
return algorithmParameterSpec;
return this.cipherWrapper.getParams();
}
/**
@ -212,7 +208,19 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 5.4.3
*/
public void setAlgorithmParameterSpec(AlgorithmParameterSpec algorithmParameterSpec) {
this.algorithmParameterSpec = algorithmParameterSpec;
this.cipherWrapper.setParams(algorithmParameterSpec);
}
/**
* 设置随机数生成器可自定义随机数种子
*
* @param random 随机数生成器可自定义随机数种子
* @return this
* @since 5.7.17
*/
public AsymmetricCrypto setRandom(SecureRandom random) {
this.cipherWrapper.setRandom(random);
return this;
}
@Override
@ -229,11 +237,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
final Key key = getKeyByType(keyType);
lock.lock();
try {
initMode(Cipher.ENCRYPT_MODE, key);
final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, key);
if (this.encryptBlockSize < 0) {
// 在引入BC库情况下自动获取块大小
final int blockSize = this.cipher.getBlockSize();
final int blockSize = cipher.getBlockSize();
if (blockSize > 0) {
this.encryptBlockSize = blockSize;
}
@ -254,11 +262,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
final Key key = getKeyByType(keyType);
lock.lock();
try {
initMode(Cipher.DECRYPT_MODE, key);
final Cipher cipher = initMode(Cipher.DECRYPT_MODE, key);
if (this.decryptBlockSize < 0) {
// 在引入BC库情况下自动获取块大小
final int blockSize = this.cipher.getBlockSize();
final int blockSize = cipher.getBlockSize();
if (blockSize > 0) {
this.decryptBlockSize = blockSize;
}
@ -281,7 +289,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 5.4.3
*/
public Cipher getCipher() {
return cipher;
return this.cipherWrapper.getCipher();
}
/**
@ -290,7 +298,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 4.5.2
*/
protected void initCipher() {
this.cipher = SecureUtil.createCipher(algorithm);
this.cipherWrapper = new CipherWrapper(this.algorithm);
}
/**
@ -309,7 +317,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
// 不足分段
if (dataLength <= maxBlockSize) {
return this.cipher.doFinal(data, 0, dataLength);
return getCipher().doFinal(data, 0, dataLength);
}
// 分段解密
@ -337,7 +345,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
// 对数据分段处理
while (remainLength > 0) {
blockSize = Math.min(remainLength, maxBlockSize);
out.write(cipher.doFinal(data, offSet, blockSize));
out.write(getCipher().doFinal(data, offSet, blockSize));
offSet += blockSize;
remainLength = dataLength - offSet;
@ -351,14 +359,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
*
* @param mode 模式可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE}
* @param key 密钥
* @return {@link Cipher}
* @throws InvalidAlgorithmParameterException 异常算法错误
* @throws InvalidKeyException 异常KEY错误
*/
private void initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
if (null != this.algorithmParameterSpec) {
cipher.init(mode, key, this.algorithmParameterSpec);
} else {
cipher.init(mode, key);
}
private Cipher initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
return this.cipherWrapper.initMode(mode, key).getCipher();
}
}

View File

@ -3,15 +3,16 @@ package cn.hutool.crypto.symmetric;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Opt;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.CipherMode;
import cn.hutool.crypto.CipherWrapper;
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.CipherInputStream;
@ -25,6 +26,7 @@ import java.io.OutputStream;
import java.io.Serializable;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ -40,18 +42,11 @@ import java.util.concurrent.locks.ReentrantLock;
public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, Serializable {
private static final long serialVersionUID = 1L;
private CipherWrapper cipherWrapper;
/**
* SecretKey 负责保存对称密钥
*/
private SecretKey secretKey;
/**
* Cipher负责完成加密或解密工作
*/
private Cipher cipher;
/**
* 加密解密参数
*/
private AlgorithmParameterSpec params;
/**
* 是否0填充
*/
@ -152,7 +147,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
this.isZeroPadding = true;
}
this.cipher = SecureUtil.createCipher(algorithm);
this.cipherWrapper = new CipherWrapper(algorithm);
return this;
}
@ -171,7 +166,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 加密或解密
*/
public Cipher getCipher() {
return cipher;
return cipherWrapper.getCipher();
}
/**
@ -181,7 +176,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setParams(AlgorithmParameterSpec params) {
this.params = params;
this.cipherWrapper.setParams(params);
return this;
}
@ -192,8 +187,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setIv(IvParameterSpec iv) {
setParams(iv);
return this;
return setParams(iv);
}
/**
@ -203,7 +197,18 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @return 自身
*/
public SymmetricCrypto setIv(byte[] iv) {
setIv(new IvParameterSpec(iv));
return setIv(new IvParameterSpec(iv));
}
/**
* 设置随机数生成器可自定义随机数种子
*
* @param random 随机数生成器可自定义随机数种子
* @return this
* @since 5.7.17
*/
public SymmetricCrypto setRandom(SecureRandom random){
this.cipherWrapper.setRandom(random);
return this;
}
@ -237,6 +242,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @since 5.6.8
*/
public byte[] update(byte[] data) {
final Cipher cipher = cipherWrapper.getCipher();
lock.lock();
try {
return cipher.update(paddingDataWithZero(data, cipher.getBlockSize()));
@ -376,11 +382,8 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
*/
private SymmetricCrypto initParams(String algorithm, AlgorithmParameterSpec paramsSpec) {
if (null == paramsSpec) {
byte[] iv = null;
final Cipher cipher = this.cipher;
if (null != cipher) {
iv = cipher.getIV();
}
byte[] iv = Opt.ofNullable(cipherWrapper)
.map(CipherWrapper::getCipher).map(Cipher::getIV).get();
// 随机IV
if (StrUtil.startWithIgnoreCase(algorithm, "PBE")) {
@ -409,13 +412,7 @@ public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor,
* @throws InvalidAlgorithmParameterException 无效算法
*/
private Cipher initMode(int mode) throws InvalidKeyException, InvalidAlgorithmParameterException {
final Cipher cipher = this.cipher;
if (null == this.params) {
cipher.init(mode, secretKey);
} else {
cipher.init(mode, secretKey, params);
}
return cipher;
return this.cipherWrapper.initMode(mode, this.secretKey).getCipher();
}
/**