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 】 增加DefaultCloneablepr#459@Gitee
* 【core 】 CollStreamUtil增加是否并行的重载pr#467@Gitee * 【core 】 CollStreamUtil增加是否并行的重载pr#467@Gitee
* 【core 】 ResourceClassLoader增加缓存pr#1959@Github * 【core 】 ResourceClassLoader增加缓存pr#1959@Github
* 【crypto 】 增加CipherWrapper增加setRandompr#1959@Github
* *
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复FileResource构造fileName参数无效问题issue#1942@Github * 【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.codec.Base64;
import cn.hutool.core.io.FastByteArrayOutputStream; import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.crypto.CipherWrapper;
import cn.hutool.crypto.CryptoException; import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.KeyUtil; import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil; import cn.hutool.crypto.SecureUtil;
@ -16,6 +17,7 @@ import java.security.InvalidKeyException;
import java.security.Key; import java.security.Key;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec; import java.security.spec.AlgorithmParameterSpec;
/** /**
@ -37,7 +39,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
/** /**
* Cipher负责完成加密或解密工作 * Cipher负责完成加密或解密工作
*/ */
protected Cipher cipher; protected CipherWrapper cipherWrapper;
/** /**
* 加密的块大小 * 加密的块大小
@ -47,12 +49,6 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* 解密的块大小 * 解密的块大小
*/ */
protected int decryptBlockSize = -1; protected int decryptBlockSize = -1;
/**
* 算法参数
*/
private AlgorithmParameterSpec algorithmParameterSpec;
// ------------------------------------------------------------------ Constructor start // ------------------------------------------------------------------ Constructor start
/** /**
@ -201,7 +197,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 5.4.3 * @since 5.4.3
*/ */
public AlgorithmParameterSpec getAlgorithmParameterSpec() { public AlgorithmParameterSpec getAlgorithmParameterSpec() {
return algorithmParameterSpec; return this.cipherWrapper.getParams();
} }
/** /**
@ -212,7 +208,19 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 5.4.3 * @since 5.4.3
*/ */
public void setAlgorithmParameterSpec(AlgorithmParameterSpec algorithmParameterSpec) { 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 @Override
@ -229,11 +237,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
final Key key = getKeyByType(keyType); final Key key = getKeyByType(keyType);
lock.lock(); lock.lock();
try { try {
initMode(Cipher.ENCRYPT_MODE, key); final Cipher cipher = initMode(Cipher.ENCRYPT_MODE, key);
if (this.encryptBlockSize < 0) { if (this.encryptBlockSize < 0) {
// 在引入BC库情况下自动获取块大小 // 在引入BC库情况下自动获取块大小
final int blockSize = this.cipher.getBlockSize(); final int blockSize = cipher.getBlockSize();
if (blockSize > 0) { if (blockSize > 0) {
this.encryptBlockSize = blockSize; this.encryptBlockSize = blockSize;
} }
@ -254,11 +262,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
final Key key = getKeyByType(keyType); final Key key = getKeyByType(keyType);
lock.lock(); lock.lock();
try { try {
initMode(Cipher.DECRYPT_MODE, key); final Cipher cipher = initMode(Cipher.DECRYPT_MODE, key);
if (this.decryptBlockSize < 0) { if (this.decryptBlockSize < 0) {
// 在引入BC库情况下自动获取块大小 // 在引入BC库情况下自动获取块大小
final int blockSize = this.cipher.getBlockSize(); final int blockSize = cipher.getBlockSize();
if (blockSize > 0) { if (blockSize > 0) {
this.decryptBlockSize = blockSize; this.decryptBlockSize = blockSize;
} }
@ -281,7 +289,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 5.4.3 * @since 5.4.3
*/ */
public Cipher getCipher() { public Cipher getCipher() {
return cipher; return this.cipherWrapper.getCipher();
} }
/** /**
@ -290,7 +298,7 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* @since 4.5.2 * @since 4.5.2
*/ */
protected void initCipher() { 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) { 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) { while (remainLength > 0) {
blockSize = Math.min(remainLength, maxBlockSize); blockSize = Math.min(remainLength, maxBlockSize);
out.write(cipher.doFinal(data, offSet, blockSize)); out.write(getCipher().doFinal(data, offSet, blockSize));
offSet += blockSize; offSet += blockSize;
remainLength = dataLength - offSet; remainLength = dataLength - offSet;
@ -351,14 +359,11 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
* *
* @param mode 模式可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE} * @param mode 模式可选{@link Cipher#ENCRYPT_MODE}或者{@link Cipher#DECRYPT_MODE}
* @param key 密钥 * @param key 密钥
* @return {@link Cipher}
* @throws InvalidAlgorithmParameterException 异常算法错误 * @throws InvalidAlgorithmParameterException 异常算法错误
* @throws InvalidKeyException 异常KEY错误 * @throws InvalidKeyException 异常KEY错误
*/ */
private void initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException { private Cipher initMode(int mode, Key key) throws InvalidAlgorithmParameterException, InvalidKeyException {
if (null != this.algorithmParameterSpec) { return this.cipherWrapper.initMode(mode, key).getCipher();
cipher.init(mode, key, this.algorithmParameterSpec);
} else {
cipher.init(mode, key);
}
} }
} }

View File

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