mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
add interface
This commit is contained in:
parent
4c237ba95e
commit
8ddf18fb7a
@ -3,7 +3,7 @@
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
# 5.7.12 (2021-09-07)
|
||||
# 5.7.12 (2021-09-08)
|
||||
|
||||
### 🐣新特性
|
||||
* 【system 】 OshiUtil增加getCurrentProcess方法
|
||||
@ -16,6 +16,7 @@
|
||||
* 【core 】 ZipReader支持Filter
|
||||
* 【all 】 Sftp、Ftp、HttpDownloader增加download重载,支持避免传输文件损坏(pr#407@Gitee)
|
||||
* 【crypto 】 AES修改构造的IvParameterSpec为AlgorithmParameterSpec(issue#1814@Gitee)
|
||||
* 【crypto 】 增加FPE(issue#1814@Gitee)
|
||||
|
||||
### 🐞Bug修复
|
||||
* 【core 】 修复ListUtil.split方法越界问题(issue#I48Q0P@Gitee)
|
||||
|
@ -99,7 +99,7 @@ public class FileUtil extends PathUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* 列出目录文件<br>
|
||||
* 列出指定路径下的目录和文件<br>
|
||||
* 给定的绝对路径不能是压缩包中的路径
|
||||
*
|
||||
* @param path 目录绝对路径或者相对路径
|
||||
|
@ -21,6 +21,8 @@ import cn.hutool.crypto.symmetric.DESede;
|
||||
import cn.hutool.crypto.symmetric.PBKDF2;
|
||||
import cn.hutool.crypto.symmetric.RC4;
|
||||
import cn.hutool.crypto.symmetric.SymmetricCrypto;
|
||||
import cn.hutool.crypto.symmetric.fpe.FPE;
|
||||
import org.bouncycastle.crypto.AlphabetMapper;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.Mac;
|
||||
@ -1108,4 +1110,18 @@ public class SecureUtil {
|
||||
public static String pbkdf2(char[] password, byte[] salt) {
|
||||
return new PBKDF2().encryptHex(password, salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* FPE(Format Preserving Encryption)实现,支持FF1和FF3-1模式。
|
||||
*
|
||||
* @param mode FPE模式枚举,可选FF1或FF3-1
|
||||
* @param key 密钥,{@code null}表示随机密钥,长度必须是16bit、24bit或32bit
|
||||
* @param mapper Alphabet字典映射,被加密的字符范围和这个映射必须一致,例如手机号、银行卡号等字段可以采用数字字母字典表
|
||||
* @param tweak Tweak是为了解决因局部加密而导致结果冲突问题,通常情况下将数据的不可变部分作为Tweak
|
||||
* @return {@link FPE}
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public static FPE fpe(FPE.FPEMode mode, byte[] key, AlphabetMapper mapper, byte[] tweak) {
|
||||
return new FPE(mode, key, mapper, tweak);
|
||||
}
|
||||
}
|
||||
|
@ -1,17 +1,5 @@
|
||||
package cn.hutool.crypto.asymmetric;
|
||||
|
||||
import cn.hutool.core.codec.BCD;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.PublicKey;
|
||||
|
||||
@ -21,9 +9,12 @@ import java.security.PublicKey;
|
||||
* @param <T> 返回自身类型
|
||||
* @author Looly
|
||||
*/
|
||||
public abstract class AbstractAsymmetricCrypto<T extends AbstractAsymmetricCrypto<T>> extends BaseAsymmetric<T> {
|
||||
// ------------------------------------------------------------------ Constructor start
|
||||
public abstract class AbstractAsymmetricCrypto<T extends AbstractAsymmetricCrypto<T>>
|
||||
extends BaseAsymmetric<T>
|
||||
implements AsymmetricEncryptor, AsymmetricDecryptor{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ------------------------------------------------------------------ Constructor start
|
||||
/**
|
||||
* 构造
|
||||
* <p>
|
||||
@ -39,296 +30,4 @@ public abstract class AbstractAsymmetricCrypto<T extends AbstractAsymmetricCrypt
|
||||
super(algorithm, privateKey, publicKey);
|
||||
}
|
||||
// ------------------------------------------------------------------ Constructor end
|
||||
|
||||
// --------------------------------------------------------------------------------- Encrypt
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public abstract byte[] encrypt(byte[] data, KeyType keyType);
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
*/
|
||||
public String encryptHex(byte[] data, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptBase64(byte[] data, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public byte[] encrypt(String data, String charset, KeyType keyType) {
|
||||
return encrypt(StrUtil.bytes(data, charset), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public byte[] encrypt(String data, Charset charset, KeyType keyType) {
|
||||
return encrypt(StrUtil.bytes(data, charset), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public byte[] encrypt(String data, KeyType keyType) {
|
||||
return encrypt(StrUtil.utf8Bytes(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptHex(String data, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptHex(String data, Charset charset, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, charset, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptBase64(String data, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptBase64(String data, Charset charset, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, charset, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的数据流
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] encrypt(InputStream data, KeyType keyType) throws IORuntimeException {
|
||||
return encrypt(IoUtil.readBytes(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的数据流
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptHex(InputStream data, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串
|
||||
*
|
||||
* @param data 被加密的数据流
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptBase64(InputStream data, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @return 加密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public String encryptBcd(String data, KeyType keyType) {
|
||||
return encryptBcd(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 加密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public String encryptBcd(String data, KeyType keyType, Charset charset) {
|
||||
return BCD.bcdToStr(encrypt(data, charset, keyType));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------- Decrypt
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
public abstract byte[] decrypt(byte[] bytes, KeyType keyType);
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param data 被解密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] decrypt(InputStream data, KeyType keyType) throws IORuntimeException {
|
||||
return decrypt(IoUtil.readBytes(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Hex或Base64字符串解密,编码为UTF-8格式
|
||||
*
|
||||
* @param data Hex(16进制)或Base64字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public byte[] decrypt(String data, KeyType keyType) {
|
||||
return decrypt(SecureUtil.decode(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为Hex(16进制)或Base64字符串
|
||||
*
|
||||
* @param data 数据,Hex(16进制)或Base64字符串
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public String decryptStr(String data, KeyType keyType, Charset charset) {
|
||||
return StrUtil.str(decrypt(data, keyType), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为Hex(16进制)或Base64字符串
|
||||
*
|
||||
* @param data 数据,Hex(16进制)或Base64字符串
|
||||
* @param keyType 密钥类型
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public String decryptStr(String data, KeyType keyType) {
|
||||
return decryptStr(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密BCD
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @return 解密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public byte[] decryptFromBcd(String data, KeyType keyType) {
|
||||
return decryptFromBcd(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组解密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 解密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public byte[] decryptFromBcd(String data, KeyType keyType, Charset charset) {
|
||||
Assert.notNull(data, "Bcd string must be not null!");
|
||||
final byte[] dataBytes = BCD.ascToBcd(StrUtil.bytes(data, charset));
|
||||
return decrypt(dataBytes, keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为BCD格式
|
||||
*
|
||||
* @param data 数据,BCD格式
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public String decryptStrFromBcd(String data, KeyType keyType, Charset charset) {
|
||||
return StrUtil.str(decryptFromBcd(data, keyType, charset), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为BCD格式,编码为UTF-8格式
|
||||
*
|
||||
* @param data 数据,BCD格式
|
||||
* @param keyType 密钥类型
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
public String decryptStrFromBcd(String data, KeyType keyType) {
|
||||
return decryptStrFromBcd(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ import java.security.spec.AlgorithmParameterSpec;
|
||||
* @author Looly
|
||||
*/
|
||||
public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Cipher负责完成加密或解密工作
|
||||
@ -223,13 +224,6 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
|
||||
// --------------------------------------------------------------------------------- Encrypt
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
@Override
|
||||
public byte[] encrypt(byte[] data, KeyType keyType) {
|
||||
final Key key = getKeyByType(keyType);
|
||||
@ -255,13 +249,6 @@ public class AsymmetricCrypto extends AbstractAsymmetricCrypto<AsymmetricCrypto>
|
||||
|
||||
// --------------------------------------------------------------------------------- Decrypt
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param data 被解密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
@Override
|
||||
public byte[] decrypt(byte[] data, KeyType keyType) {
|
||||
final Key key = getKeyByType(keyType);
|
||||
|
@ -0,0 +1,137 @@
|
||||
package cn.hutool.crypto.asymmetric;
|
||||
|
||||
import cn.hutool.core.codec.BCD;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 非对称解密器接口,提供:
|
||||
* <ul>
|
||||
* <li>从bytes解密</li>
|
||||
* <li>从Hex(16进制)解密</li>
|
||||
* <li>从Base64解密</li>
|
||||
* <li>从BCD解密</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public interface AsymmetricDecryptor {
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
byte[] decrypt(byte[] bytes, KeyType keyType);
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param data 被解密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
default byte[] decrypt(InputStream data, KeyType keyType) throws IORuntimeException {
|
||||
return decrypt(IoUtil.readBytes(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Hex或Base64字符串解密,编码为UTF-8格式
|
||||
*
|
||||
* @param data Hex(16进制)或Base64字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 解密后的bytes
|
||||
* @since 4.5.2
|
||||
*/
|
||||
default byte[] decrypt(String data, KeyType keyType) {
|
||||
return decrypt(SecureUtil.decode(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为Hex(16进制)或Base64字符串
|
||||
*
|
||||
* @param data 数据,Hex(16进制)或Base64字符串
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
default String decryptStr(String data, KeyType keyType, Charset charset) {
|
||||
return StrUtil.str(decrypt(data, keyType), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为Hex(16进制)或Base64字符串
|
||||
*
|
||||
* @param data 数据,Hex(16进制)或Base64字符串
|
||||
* @param keyType 密钥类型
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
default String decryptStr(String data, KeyType keyType) {
|
||||
return decryptStr(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密BCD
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @return 解密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
default byte[] decryptFromBcd(String data, KeyType keyType) {
|
||||
return decryptFromBcd(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组解密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 解密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
default byte[] decryptFromBcd(String data, KeyType keyType, Charset charset) {
|
||||
Assert.notNull(data, "Bcd string must be not null!");
|
||||
final byte[] dataBytes = BCD.ascToBcd(StrUtil.bytes(data, charset));
|
||||
return decrypt(dataBytes, keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为BCD格式
|
||||
*
|
||||
* @param data 数据,BCD格式
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
default String decryptStrFromBcd(String data, KeyType keyType, Charset charset) {
|
||||
return StrUtil.str(decryptFromBcd(data, keyType, charset), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,密文需为BCD格式,编码为UTF-8格式
|
||||
*
|
||||
* @param data 数据,BCD格式
|
||||
* @param keyType 密钥类型
|
||||
* @return 解密后的密文
|
||||
* @since 4.5.2
|
||||
*/
|
||||
default String decryptStrFromBcd(String data, KeyType keyType) {
|
||||
return decryptStrFromBcd(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
}
|
@ -0,0 +1,205 @@
|
||||
package cn.hutool.crypto.asymmetric;
|
||||
|
||||
import cn.hutool.core.codec.BCD;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 非对称加密器接口,提供:
|
||||
* <ul>
|
||||
* <li>加密为bytes</li>
|
||||
* <li>加密为Hex(16进制)</li>
|
||||
* <li>加密为Base64</li>
|
||||
* <li>加密为BCD</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public interface AsymmetricEncryptor {
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
byte[] encrypt(byte[] data, KeyType keyType);
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
*/
|
||||
default String encryptHex(byte[] data, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptBase64(byte[] data, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
default byte[] encrypt(String data, String charset, KeyType keyType) {
|
||||
return encrypt(StrUtil.bytes(data, charset), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
default byte[] encrypt(String data, Charset charset, KeyType keyType) {
|
||||
return encrypt(StrUtil.bytes(data, charset), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
default byte[] encrypt(String data, KeyType keyType) {
|
||||
return encrypt(StrUtil.utf8Bytes(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptHex(String data, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptHex(String data, Charset charset, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, charset, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptBase64(String data, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptBase64(String data, Charset charset, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, charset, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的数据流
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return 加密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
default byte[] encrypt(InputStream data, KeyType keyType) throws IORuntimeException {
|
||||
return encrypt(IoUtil.readBytes(data), keyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Hex字符串
|
||||
*
|
||||
* @param data 被加密的数据流
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Hex字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptHex(InputStream data, KeyType keyType) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码为Base64字符串
|
||||
*
|
||||
* @param data 被加密的数据流
|
||||
* @param keyType 私钥或公钥 {@link KeyType}
|
||||
* @return Base64字符串
|
||||
* @since 4.0.1
|
||||
*/
|
||||
default String encryptBase64(InputStream data, KeyType keyType) {
|
||||
return Base64.encode(encrypt(data, keyType));
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @return 加密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
default String encryptBcd(String data, KeyType keyType) {
|
||||
return encryptBcd(data, keyType, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分组加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @param keyType 密钥类型
|
||||
* @param charset 加密前编码
|
||||
* @return 加密后的密文
|
||||
* @since 4.1.0
|
||||
*/
|
||||
default String encryptBcd(String data, KeyType keyType, Charset charset) {
|
||||
return BCD.bcdToStr(encrypt(data, charset, keyType));
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.KeyUtil;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.security.Key;
|
||||
import java.security.KeyPair;
|
||||
import java.security.PrivateKey;
|
||||
@ -18,7 +19,8 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
* @author Looly
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public class BaseAsymmetric<T extends BaseAsymmetric<T>> {
|
||||
public class BaseAsymmetric<T extends BaseAsymmetric<T>> implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 算法
|
||||
|
@ -14,6 +14,7 @@ import java.security.PublicKey;
|
||||
* @since 5.3.10
|
||||
*/
|
||||
public class ECIES extends AsymmetricCrypto{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 默认的ECIES算法 */
|
||||
private static final String ALGORITHM_ECIES = "ECIES";
|
||||
|
@ -28,6 +28,7 @@ import java.security.spec.RSAPublicKeySpec;
|
||||
*
|
||||
*/
|
||||
public class RSA extends AsymmetricCrypto {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 默认的RSA算法 */
|
||||
private static final AsymmetricAlgorithm ALGORITHM_RSA = AsymmetricAlgorithm.RSA_ECB_PKCS1;
|
||||
|
@ -40,6 +40,7 @@ import java.security.PublicKey;
|
||||
* @since 4.3.2
|
||||
*/
|
||||
public class SM2 extends AbstractAsymmetricCrypto<SM2> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 算法EC
|
||||
|
@ -29,6 +29,7 @@ import java.util.Set;
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public class Sign extends BaseAsymmetric<Sign> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 签名,用于签名和验证 */
|
||||
protected Signature signature;
|
||||
|
@ -1,11 +1,9 @@
|
||||
package cn.hutool.crypto.symmetric;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@ -25,7 +23,6 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
@ -40,7 +37,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class SymmetricCrypto implements Serializable {
|
||||
public class SymmetricCrypto implements SymmetricEncryptor, SymmetricDecryptor, Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
@ -159,6 +156,24 @@ public class SymmetricCrypto implements Serializable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得对称密钥
|
||||
*
|
||||
* @return 获得对称密钥
|
||||
*/
|
||||
public SecretKey getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得加密或解密器
|
||||
*
|
||||
* @return 加密或解密
|
||||
*/
|
||||
public Cipher getCipher() {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 {@link AlgorithmParameterSpec},通常用于加盐或偏移向量
|
||||
*
|
||||
@ -246,12 +261,7 @@ public class SymmetricCrypto implements Serializable {
|
||||
|
||||
// --------------------------------------------------------------------------------- Encrypt
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
@Override
|
||||
public byte[] encrypt(byte[] data) {
|
||||
lock.lock();
|
||||
try {
|
||||
@ -264,15 +274,7 @@ public class SymmetricCrypto implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,针对大数据量,可选结束后是否关闭流
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param out 输出流,可以是文件或网络位置
|
||||
* @param isClose 是否关闭流
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.6.3
|
||||
*/
|
||||
@Override
|
||||
public void encrypt(InputStream data, OutputStream out, boolean isClose) throws IORuntimeException {
|
||||
lock.lock();
|
||||
CipherOutputStream cipherOutputStream = null;
|
||||
@ -305,165 +307,9 @@ public class SymmetricCrypto implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
public String encryptHex(byte[] data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @return 加密后的Base64
|
||||
* @since 4.0.1
|
||||
*/
|
||||
public String encryptBase64(byte[] data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public byte[] encrypt(String data, String charset) {
|
||||
return encrypt(StrUtil.bytes(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public byte[] encrypt(String data, Charset charset) {
|
||||
return encrypt(StrUtil.bytes(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Hex
|
||||
* @since 4.5.12
|
||||
*/
|
||||
public String encryptHex(String data, String charset) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Hex
|
||||
* @since 4.5.12
|
||||
*/
|
||||
public String encryptHex(String data, Charset charset) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
public String encryptBase64(String data, String charset) {
|
||||
return Base64.encode(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Base64
|
||||
* @since 4.5.12
|
||||
*/
|
||||
public String encryptBase64(String data, Charset charset) {
|
||||
return Base64.encode(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
public byte[] encrypt(String data) {
|
||||
return encrypt(StrUtil.bytes(data, CharsetUtil.CHARSET_UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
public String encryptHex(String data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
public String encryptBase64(String data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,加密后关闭流
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] encrypt(InputStream data) throws IORuntimeException {
|
||||
return encrypt(IoUtil.readBytes(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
public String encryptHex(InputStream data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
public String encryptBase64(InputStream data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------- Decrypt
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
@Override
|
||||
public byte[] decrypt(byte[] bytes) {
|
||||
final int blockSize;
|
||||
final byte[] decryptData;
|
||||
@ -482,15 +328,7 @@ public class SymmetricCrypto implements Serializable {
|
||||
return removePadding(decryptData, blockSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密,针对大数据量,结束后不关闭流
|
||||
*
|
||||
* @param data 加密的字符串
|
||||
* @param out 输出流,可以是文件或网络位置
|
||||
* @param isClose 是否关闭流,包括输入和输出流
|
||||
* @throws IORuntimeException IO异常
|
||||
* @since 5.6.3
|
||||
*/
|
||||
@Override
|
||||
public void decrypt(InputStream data, OutputStream out, boolean isClose) throws IORuntimeException {
|
||||
lock.lock();
|
||||
CipherInputStream cipherInputStream = null;
|
||||
@ -520,110 +358,8 @@ public class SymmetricCrypto implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @param charset 解密后的charset
|
||||
* @return 解密后的String
|
||||
*/
|
||||
public String decryptStr(byte[] bytes, Charset charset) {
|
||||
return StrUtil.str(decrypt(bytes), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,默认UTF-8编码
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @return 解密后的String
|
||||
*/
|
||||
public String decryptStr(byte[] bytes) {
|
||||
return decryptStr(bytes, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Hex(16进制)或Base64表示的字符串
|
||||
*
|
||||
* @param data 被解密的String,必须为16进制字符串或Base64表示形式
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
public byte[] decrypt(String data) {
|
||||
return decrypt(SecureUtil.decode(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Hex(16进制)或Base64表示的字符串
|
||||
*
|
||||
* @param data 被解密的String
|
||||
* @param charset 解密后的charset
|
||||
* @return 解密后的String
|
||||
*/
|
||||
public String decryptStr(String data, Charset charset) {
|
||||
return StrUtil.str(decrypt(data), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Hex(16进制)或Base64表示的字符串,默认UTF-8编码
|
||||
*
|
||||
* @param data 被解密的String
|
||||
* @return 解密后的String
|
||||
*/
|
||||
public String decryptStr(String data) {
|
||||
return decryptStr(data, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密,会关闭流
|
||||
*
|
||||
* @param data 被解密的bytes
|
||||
* @return 解密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
public byte[] decrypt(InputStream data) throws IORuntimeException {
|
||||
return decrypt(IoUtil.readBytes(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密,不会关闭流
|
||||
*
|
||||
* @param data 被解密的InputStream
|
||||
* @param charset 解密后的charset
|
||||
* @return 解密后的String
|
||||
*/
|
||||
public String decryptStr(InputStream data, Charset charset) {
|
||||
return StrUtil.str(decrypt(data), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param data 被解密的InputStream
|
||||
* @return 解密后的String
|
||||
*/
|
||||
public String decryptStr(InputStream data) {
|
||||
return decryptStr(data, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------- Getters
|
||||
|
||||
/**
|
||||
* 获得对称密钥
|
||||
*
|
||||
* @return 获得对称密钥
|
||||
*/
|
||||
public SecretKey getSecretKey() {
|
||||
return secretKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得加密或解密器
|
||||
*
|
||||
* @return 加密或解密
|
||||
*/
|
||||
public Cipher getCipher() {
|
||||
return cipher;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------- Private method start
|
||||
|
||||
/**
|
||||
@ -740,7 +476,7 @@ public class SymmetricCrypto implements Serializable {
|
||||
* @param blockSize 块大小
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private void copyForZeroPadding(CipherInputStream in, OutputStream out, int blockSize) throws IOException {
|
||||
private static void copyForZeroPadding(CipherInputStream in, OutputStream out, int blockSize) throws IOException {
|
||||
int n = 1;
|
||||
if (IoUtil.DEFAULT_BUFFER_SIZE > blockSize) {
|
||||
n = Math.max(n, IoUtil.DEFAULT_BUFFER_SIZE / blockSize);
|
||||
|
@ -0,0 +1,126 @@
|
||||
package cn.hutool.crypto.symmetric;
|
||||
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 对称解密器接口,提供:
|
||||
* <ul>
|
||||
* <li>从bytes解密</li>
|
||||
* <li>从Hex(16进制)解密</li>
|
||||
* <li>从Base64解密</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public interface SymmetricDecryptor {
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
byte[] decrypt(byte[] bytes);
|
||||
|
||||
/**
|
||||
* 解密,针对大数据量,结束后不关闭流
|
||||
*
|
||||
* @param data 加密的字符串
|
||||
* @param out 输出流,可以是文件或网络位置
|
||||
* @param isClose 是否关闭流,包括输入和输出流
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
void decrypt(InputStream data, OutputStream out, boolean isClose);
|
||||
|
||||
/**
|
||||
* 解密为字符串
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @param charset 解密后的charset
|
||||
* @return 解密后的String
|
||||
*/
|
||||
default String decryptStr(byte[] bytes, Charset charset) {
|
||||
return StrUtil.str(decrypt(bytes), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密为字符串,默认UTF-8编码
|
||||
*
|
||||
* @param bytes 被解密的bytes
|
||||
* @return 解密后的String
|
||||
*/
|
||||
default String decryptStr(byte[] bytes) {
|
||||
return decryptStr(bytes, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Hex(16进制)或Base64表示的字符串
|
||||
*
|
||||
* @param data 被解密的String,必须为16进制字符串或Base64表示形式
|
||||
* @return 解密后的bytes
|
||||
*/
|
||||
default byte[] decrypt(String data) {
|
||||
return decrypt(SecureUtil.decode(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Hex(16进制)或Base64表示的字符串
|
||||
*
|
||||
* @param data 被解密的String
|
||||
* @param charset 解密后的charset
|
||||
* @return 解密后的String
|
||||
*/
|
||||
default String decryptStr(String data, Charset charset) {
|
||||
return StrUtil.str(decrypt(data), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密Hex(16进制)或Base64表示的字符串,默认UTF-8编码
|
||||
*
|
||||
* @param data 被解密的String
|
||||
* @return 解密后的String
|
||||
*/
|
||||
default String decryptStr(String data) {
|
||||
return decryptStr(data, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密,会关闭流
|
||||
*
|
||||
* @param data 被解密的bytes
|
||||
* @return 解密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
default byte[] decrypt(InputStream data) throws IORuntimeException {
|
||||
return decrypt(IoUtil.readBytes(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密,不会关闭流
|
||||
*
|
||||
* @param data 被解密的InputStream
|
||||
* @param charset 解密后的charset
|
||||
* @return 解密后的String
|
||||
*/
|
||||
default String decryptStr(InputStream data, Charset charset) {
|
||||
return StrUtil.str(decrypt(data), charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param data 被解密的InputStream
|
||||
* @return 解密后的String
|
||||
*/
|
||||
default String decryptStr(InputStream data) {
|
||||
return decryptStr(data, CharsetUtil.CHARSET_UTF_8);
|
||||
}
|
||||
}
|
@ -0,0 +1,192 @@
|
||||
package cn.hutool.crypto.symmetric;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.io.IORuntimeException;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* 对称加密器接口,提供:
|
||||
* <ul>
|
||||
* <li>加密为bytes</li>
|
||||
* <li>加密为Hex(16进制)</li>
|
||||
* <li>加密为Base64</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public interface SymmetricEncryptor {
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的bytes
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
byte[] encrypt(byte[] data);
|
||||
|
||||
/**
|
||||
* 加密,针对大数据量,可选结束后是否关闭流
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param out 输出流,可以是文件或网络位置
|
||||
* @param isClose 是否关闭流
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
void encrypt(InputStream data, OutputStream out, boolean isClose);
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
default String encryptHex(byte[] data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 数据
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
default String encryptBase64(byte[] data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
default byte[] encrypt(String data, String charset) {
|
||||
return encrypt(StrUtil.bytes(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
default byte[] encrypt(String data, Charset charset) {
|
||||
return encrypt(StrUtil.bytes(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
default String encryptHex(String data, String charset) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
default String encryptHex(String data, Charset charset) {
|
||||
return HexUtil.encodeHexStr(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
default String encryptBase64(String data, String charset) {
|
||||
return Base64.encode(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @param charset 编码
|
||||
* @return 加密后的Base64
|
||||
* @since 4.5.12
|
||||
*/
|
||||
default String encryptBase64(String data, Charset charset) {
|
||||
return Base64.encode(encrypt(data, charset));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的bytes
|
||||
*/
|
||||
default byte[] encrypt(String data) {
|
||||
return encrypt(StrUtil.bytes(data, CharsetUtil.CHARSET_UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
default String encryptHex(String data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,使用UTF-8编码
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
default String encryptBase64(String data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密,加密后关闭流
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的bytes
|
||||
* @throws IORuntimeException IO异常
|
||||
*/
|
||||
default byte[] encrypt(InputStream data) throws IORuntimeException {
|
||||
return encrypt(IoUtil.readBytes(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Hex
|
||||
*/
|
||||
default String encryptHex(InputStream data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 被加密的字符串
|
||||
* @return 加密后的Base64
|
||||
*/
|
||||
default String encryptBase64(InputStream data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
package cn.hutool.crypto.symmetric.fpe;
|
||||
|
||||
import cn.hutool.crypto.KeyUtil;
|
||||
import cn.hutool.crypto.Padding;
|
||||
import cn.hutool.crypto.symmetric.AES;
|
||||
import org.bouncycastle.crypto.AlphabetMapper;
|
||||
import org.bouncycastle.jcajce.spec.FPEParameterSpec;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* FPE(Format Preserving Encryption)实现,支持FF1和FF3-1模式。<br>
|
||||
* 相关介绍见:https://anquan.baidu.com/article/193
|
||||
*
|
||||
* <p>
|
||||
* FPE是一种格式保持与明文相同的加密方式,通常用于数据脱敏中,因为它需要保持明密文的格式相同,
|
||||
* 例如社保号经过加密之后并不是固定长度的杂文,而是相同格式、打乱的号码,依然是社保号的格式。
|
||||
* </p>
|
||||
* <p>
|
||||
* FPE算法可以保证:
|
||||
*
|
||||
* <ul>
|
||||
* <li>数据长度不变。加密前长度是N,加密后长度仍然是N</li>
|
||||
* <li>数据类型不变,加密前是数字类型,加密后仍然是数字类型</li>
|
||||
* <li>加密过程可逆,加密后的数据可以通过密钥解密还原原始数据</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author looly
|
||||
* @since 5.7.12
|
||||
*/
|
||||
public class FPE implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// 映射字符表,规定了明文和密文的字符范围
|
||||
private final AES aes;
|
||||
private final AlphabetMapper mapper;
|
||||
|
||||
/**
|
||||
* 构造,使用空的Tweak
|
||||
*
|
||||
* @param mode FPE模式枚举,可选FF1或FF3-1
|
||||
* @param key 密钥,{@code null}表示随机密钥,长度必须是16bit、24bit或32bit
|
||||
* @param mapper Alphabet字典映射,被加密的字符范围和这个映射必须一致,例如手机号、银行卡号等字段可以采用数字字母字典表
|
||||
*/
|
||||
public FPE(FPEMode mode, byte[] key, AlphabetMapper mapper) {
|
||||
this(mode, key, mapper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param mode FPE模式枚举,可选FF1或FF3-1
|
||||
* @param key 密钥,{@code null}表示随机密钥,长度必须是16bit、24bit或32bit
|
||||
* @param mapper Alphabet字典映射,被加密的字符范围和这个映射必须一致,例如手机号、银行卡号等字段可以采用数字字母字典表
|
||||
* @param tweak Tweak是为了解决因局部加密而导致结果冲突问题,通常情况下将数据的不可变部分作为Tweak
|
||||
*/
|
||||
public FPE(FPEMode mode, byte[] key, AlphabetMapper mapper, byte[] tweak) {
|
||||
if (null == mode) {
|
||||
mode = FPEMode.FF1;
|
||||
}
|
||||
|
||||
if(null == tweak){
|
||||
switch (mode){
|
||||
case FF1:
|
||||
tweak = new byte[0];
|
||||
break;
|
||||
case FF3_1:
|
||||
// FF3-1要求必须为56 bits
|
||||
tweak = new byte[7];
|
||||
}
|
||||
}
|
||||
this.aes = new AES(mode.value, Padding.NoPadding.name(),
|
||||
KeyUtil.generateKey(mode.value, key),
|
||||
new FPEParameterSpec(mapper.getRadix(), tweak));
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围
|
||||
* @return 密文结果
|
||||
*/
|
||||
public String encrypt(String data) {
|
||||
if (null == data) {
|
||||
return null;
|
||||
}
|
||||
return new String(encrypt(data.toCharArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围
|
||||
* @return 密文结果
|
||||
*/
|
||||
public char[] encrypt(char[] data) {
|
||||
if (null == data) {
|
||||
return null;
|
||||
}
|
||||
// 通过 mapper 将密文输出处理为原始格式
|
||||
return mapper.convertToChars(aes.encrypt(mapper.convertToIndexes(data)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密
|
||||
*
|
||||
* @param data 密文数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围
|
||||
* @return 明文结果
|
||||
*/
|
||||
public String decrypt(String data) {
|
||||
if (null == data) {
|
||||
return null;
|
||||
}
|
||||
return new String(decrypt(data.toCharArray()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 加密
|
||||
*
|
||||
* @param data 密文数据,数据必须在构造传入的{@link AlphabetMapper}中定义的范围
|
||||
* @return 明文结果
|
||||
*/
|
||||
public char[] decrypt(char[] data) {
|
||||
if (null == data) {
|
||||
return null;
|
||||
}
|
||||
// 通过 mapper 将密文输出处理为原始格式
|
||||
return mapper.convertToChars(aes.decrypt(mapper.convertToIndexes(data)));
|
||||
}
|
||||
|
||||
/**
|
||||
* FPE模式<br>
|
||||
* FPE包括两种模式:FF1和FF3(FF2弃用),核心均为Feistel网络结构。
|
||||
*
|
||||
* @author looly
|
||||
*/
|
||||
public enum FPEMode {
|
||||
/**
|
||||
* FF1模式
|
||||
*/
|
||||
FF1("FF1"),
|
||||
/**
|
||||
* FF3-1 模式
|
||||
*/
|
||||
FF3_1("FF3-1");
|
||||
|
||||
private final String value;
|
||||
|
||||
FPEMode(String name) {
|
||||
this.value = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模式名
|
||||
*
|
||||
* @return 模式名
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,14 +7,11 @@ import cn.hutool.crypto.KeyUtil;
|
||||
import cn.hutool.crypto.Mode;
|
||||
import cn.hutool.crypto.Padding;
|
||||
import cn.hutool.crypto.symmetric.AES;
|
||||
import org.bouncycastle.crypto.util.BasicAlphabetMapper;
|
||||
import org.bouncycastle.jcajce.spec.FPEParameterSpec;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.SecureRandom;
|
||||
|
||||
public class AESTest {
|
||||
@ -117,33 +114,6 @@ public class AESTest {
|
||||
Assert.assertEquals(content, decryptStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 见:https://github.com/dromara/hutool/issues/1814
|
||||
*/
|
||||
@Test
|
||||
public void fpeTest() {
|
||||
// 映射字符表,规定了明文和密文的字符范围
|
||||
BasicAlphabetMapper numberMapper = new BasicAlphabetMapper("0123456789");
|
||||
|
||||
// 初始化 aes 密钥
|
||||
byte[] keyBytes = RandomUtil.randomBytes(16);
|
||||
|
||||
AES aes = new AES("FF1", "NoPadding",
|
||||
new SecretKeySpec(keyBytes, "FF1"),
|
||||
new FPEParameterSpec(numberMapper.getRadix(), new byte[]{}));
|
||||
|
||||
// 原始数据
|
||||
String phone = "13534534567";
|
||||
// 加密
|
||||
byte[] inputDataByte = numberMapper.convertToIndexes(phone.toCharArray());
|
||||
byte[] encrypt = aes.encrypt(inputDataByte);
|
||||
|
||||
// 通过 mapper 将密文输出处理为原始格式
|
||||
char[] encryptChars = numberMapper.convertToChars(encrypt);
|
||||
// 手机号码加密: 13534534567 -> 49725950626
|
||||
Assert.assertEquals(phone.length(), encryptChars.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* 见:https://blog.csdn.net/weixin_42468911/article/details/114358682
|
||||
*/
|
||||
|
@ -0,0 +1,48 @@
|
||||
package cn.hutool.crypto.test.symmetric.fpe;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.crypto.symmetric.fpe.FPE;
|
||||
import org.bouncycastle.crypto.util.BasicAlphabetMapper;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FPETest {
|
||||
|
||||
@Test
|
||||
public void ff1Test(){
|
||||
// 映射字符表,规定了明文和密文的字符范围
|
||||
BasicAlphabetMapper numberMapper = new BasicAlphabetMapper("A0123456789");
|
||||
// 初始化 aes 密钥
|
||||
byte[] keyBytes = RandomUtil.randomBytes(16);
|
||||
|
||||
final FPE fpe = new FPE(FPE.FPEMode.FF1, keyBytes, numberMapper, null);
|
||||
|
||||
// 原始数据
|
||||
String phone = RandomUtil.randomString("A0123456789", 13);
|
||||
final String encrypt = fpe.encrypt(phone);
|
||||
// 加密后与原密文长度一致
|
||||
Assert.assertEquals(phone.length(), encrypt.length());
|
||||
|
||||
final String decrypt = fpe.decrypt(encrypt);
|
||||
Assert.assertEquals(phone, decrypt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ff3Test(){
|
||||
// 映射字符表,规定了明文和密文的字符范围
|
||||
BasicAlphabetMapper numberMapper = new BasicAlphabetMapper("A0123456789");
|
||||
// 初始化 aes 密钥
|
||||
byte[] keyBytes = RandomUtil.randomBytes(16);
|
||||
|
||||
final FPE fpe = new FPE(FPE.FPEMode.FF3_1, keyBytes, numberMapper, null);
|
||||
|
||||
// 原始数据
|
||||
String phone = RandomUtil.randomString("A0123456789", 13);
|
||||
final String encrypt = fpe.encrypt(phone);
|
||||
// 加密后与原密文长度一致
|
||||
Assert.assertEquals(phone.length(), encrypt.length());
|
||||
|
||||
final String decrypt = fpe.decrypt(encrypt);
|
||||
Assert.assertEquals(phone, decrypt);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user