480 lines
16 KiB
Java
480 lines
16 KiB
Java
package top.octopusyan.utils;
|
||
|
||
import cn.hutool.crypto.ProviderFactory;
|
||
import cn.hutool.crypto.SecureUtil;
|
||
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
|
||
import org.apache.commons.lang3.StringUtils;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import sun.misc.BASE64Encoder;
|
||
|
||
import javax.crypto.Cipher;
|
||
import javax.crypto.NoSuchPaddingException;
|
||
import javax.crypto.SecretKeyFactory;
|
||
import javax.crypto.spec.DESKeySpec;
|
||
import javax.crypto.spec.SecretKeySpec;
|
||
import java.io.*;
|
||
import java.math.BigInteger;
|
||
import java.nio.charset.Charset;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.security.*;
|
||
import java.security.spec.PKCS8EncodedKeySpec;
|
||
import java.security.spec.X509EncodedKeySpec;
|
||
import java.util.Arrays;
|
||
|
||
/**
|
||
* @author : octopus yan
|
||
* @email : octopus_yan@foxmail.com
|
||
* @description : 常用加密工具类
|
||
* @create : 2021-03-18 19:03
|
||
*/
|
||
public class EncryptionUtil {
|
||
private static final String defaultPassword = "yanfrp";
|
||
private static Logger logger = LoggerFactory.getLogger(EncryptionUtil.class);
|
||
|
||
private static BASE64Encoder BASE64Encoder;
|
||
private static MessageDigest MessageDigest_SHA1;
|
||
private static MessageDigest MessageDigest_MD5;
|
||
private static Cipher Cipher_ECB_MOB;
|
||
private static Cipher Cipher_ALGORITHM_MODE_PADDING;
|
||
private static Signature Signature_SHA256_RSA;
|
||
|
||
/**
|
||
* 密钥算法
|
||
*/
|
||
private static final String DES = "DES";
|
||
private static final String AES = "AES";
|
||
private static final String RES = "RES";
|
||
private static final String RSA = "RSA";
|
||
/**
|
||
* 加解密算法/工作模式/填充方式
|
||
*/
|
||
private static final String ECB_MOB = "DES/ECB/PKCS5Padding";
|
||
// private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS7Padding";
|
||
private static final String ALGORITHM_MODE_PADDING = "AES/ECB/PKCS5Padding";
|
||
|
||
private static final Charset UTF_8 = StandardCharsets.UTF_8;
|
||
|
||
private static final char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
|
||
'E', 'F'};
|
||
private static final char hexDigitsLower[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c',
|
||
'd', 'e', 'f'};
|
||
|
||
public static void init() {
|
||
|
||
BASE64Encoder = new BASE64Encoder();
|
||
try {
|
||
MessageDigest_SHA1 = MessageDigest.getInstance("SHA-1");
|
||
MessageDigest_MD5 = MessageDigest.getInstance("MD5");
|
||
Cipher_ECB_MOB = Cipher.getInstance(ECB_MOB);
|
||
Cipher_ALGORITHM_MODE_PADDING = Cipher.getInstance(ALGORITHM_MODE_PADDING);
|
||
Signature_SHA256_RSA = Signature.getInstance("SHA256WithRSA");
|
||
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||
e.printStackTrace();
|
||
}
|
||
|
||
}
|
||
|
||
public static String getDefaultPassword() {
|
||
return getSHA(defaultPassword + getMessageDigestString("frp." + defaultPassword, hexDigits, MessageDigest_SHA1));
|
||
}
|
||
|
||
public static String decodeAppData(String str) {
|
||
try {
|
||
return DESdecode(str, getDefaultPassword());
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public static String encodeAppData(String str) {
|
||
try {
|
||
return DESencode(str, getDefaultPassword());
|
||
} catch (Exception e) {
|
||
e.printStackTrace();
|
||
return null;
|
||
}
|
||
}
|
||
|
||
public static String getSha1(String str) {
|
||
if (str == null || str.length() == 0) {
|
||
return null;
|
||
}
|
||
return getMessageDigestString(str, hexDigitsLower, MessageDigest_SHA1);
|
||
}
|
||
|
||
public static String getSHA(String spara) {
|
||
String sRtn;
|
||
|
||
byte[] plainText = spara.getBytes(UTF_8);
|
||
// 开始使用算法
|
||
MessageDigest_SHA1.update(plainText);
|
||
// 输出算法运算结果
|
||
sRtn = BASE64Encoder.encode(MessageDigest_SHA1.digest());
|
||
|
||
return sRtn;
|
||
}
|
||
|
||
/**
|
||
* DES加密
|
||
*
|
||
* @param data 加密内容
|
||
* @param password 秘钥
|
||
*/
|
||
public static String DESencode(String data, String password) throws Exception {
|
||
byte[] pasByte;
|
||
|
||
Key key = getDESKey(password);
|
||
Cipher_ECB_MOB.init(Cipher.ENCRYPT_MODE, key);
|
||
pasByte = Cipher_ECB_MOB.doFinal(data.getBytes(UTF_8));
|
||
|
||
return Base64.encode(pasByte);
|
||
}
|
||
|
||
/**
|
||
* DES解密
|
||
*
|
||
* @param data 加密内容
|
||
* @param password 秘钥
|
||
* @return
|
||
*/
|
||
public static String DESdecode(String data, String password) throws Exception {
|
||
byte[] pasByte;
|
||
Key key = getDESKey(password);
|
||
Cipher_ECB_MOB.init(Cipher.DECRYPT_MODE, key);
|
||
byte[] x = Base64.decode(data);
|
||
pasByte = Cipher_ECB_MOB.doFinal(x);
|
||
return new String(pasByte, UTF_8);
|
||
}
|
||
|
||
private static Key getDESKey(String password) throws Exception {
|
||
byte[] DESkey = password.getBytes(UTF_8);
|
||
DESKeySpec keySpec = new DESKeySpec(DESkey);
|
||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);
|
||
return keyFactory.generateSecret(keySpec);
|
||
}
|
||
|
||
/**
|
||
* AES加密
|
||
*
|
||
* @param data 加密内容
|
||
* @param password 加密密码
|
||
*/
|
||
public static String AESencode(String data, String password) throws Exception {
|
||
byte[] result;
|
||
Security.addProvider(ProviderFactory.createBouncyCastleProvider());
|
||
// 创建密码器
|
||
// 初始化为加密模式的密码
|
||
Cipher_ALGORITHM_MODE_PADDING.init(Cipher.ENCRYPT_MODE, getSecretKey(password));
|
||
// 加密
|
||
result = Cipher_ALGORITHM_MODE_PADDING.doFinal(data.getBytes());
|
||
|
||
return Base64.encode(result);
|
||
}
|
||
|
||
/**
|
||
* AES解密
|
||
*
|
||
* @param base64Data 解密内容
|
||
* @param password 解密密码
|
||
*/
|
||
public static String AESdecode(String base64Data, String password) throws Exception {
|
||
byte[] result;
|
||
Security.addProvider(ProviderFactory.createBouncyCastleProvider());
|
||
// 使用密钥初始化,设置为解密模式
|
||
Cipher_ALGORITHM_MODE_PADDING.init(Cipher.DECRYPT_MODE, getSecretKey(password));
|
||
// 执行操作
|
||
result = Cipher_ALGORITHM_MODE_PADDING.doFinal(Base64.decode(base64Data));
|
||
|
||
return new String(result, UTF_8);
|
||
}
|
||
|
||
/**
|
||
* 生成AES加密秘钥
|
||
*
|
||
* @return
|
||
*/
|
||
private static SecretKeySpec getSecretKey(String password) {
|
||
return new SecretKeySpec(SecureUtil.md5(password).toLowerCase().getBytes(), AES);
|
||
}
|
||
|
||
/**
|
||
* 对字符串 MD5 无盐值加密
|
||
*
|
||
* @param plainText 传入要加密的字符串
|
||
* @return MD5加密后生成32位(小写字母 + 数字)字符串
|
||
*/
|
||
public static String MD5Lower(String plainText) {
|
||
// 使用指定的字节更新摘要
|
||
MessageDigest_MD5.update(plainText.getBytes());
|
||
// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
|
||
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值
|
||
return new BigInteger(1, MessageDigest_MD5.digest()).toString(16);
|
||
}
|
||
|
||
|
||
/**
|
||
* 对字符串 MD5 加密
|
||
*
|
||
* @param plainText 传入要加密的字符串
|
||
* @return MD5加密后生成32位(大写字母 + 数字)字符串
|
||
*/
|
||
public static String MD5Upper(String plainText) {
|
||
// 使用指定的字节更新摘要
|
||
MessageDigest_MD5.update(plainText.getBytes());
|
||
// 获得密文
|
||
byte[] mdResult = MessageDigest_MD5.digest();
|
||
// 把密文转换成十六进制的字符串形式
|
||
return getHexString(hexDigitsLower, mdResult);
|
||
}
|
||
|
||
/**
|
||
* 对字符串 MD5 加盐值加密
|
||
*
|
||
* @param plainText 传入要加密的字符串
|
||
* @param saltValue 传入要加的盐值
|
||
* @return MD5加密后生成32位(小写字母 + 数字)字符串
|
||
*/
|
||
public static String MD5Lower(String plainText, String saltValue) {
|
||
// 使用指定的字节更新摘要
|
||
MessageDigest_MD5.update(plainText.getBytes());
|
||
MessageDigest_MD5.update(saltValue.getBytes());
|
||
|
||
// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
|
||
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值。1 固定值
|
||
return new BigInteger(1, MessageDigest_MD5.digest()).toString(16);
|
||
}
|
||
|
||
/**
|
||
* 对字符串 MD5 加盐值加密
|
||
*
|
||
* @param plainText 传入要加密的字符串
|
||
* @param saltValue 传入要加的盐值
|
||
* @return MD5加密后生成32位(大写字母 + 数字)字符串
|
||
*/
|
||
public static String MD5Upper(String plainText, String saltValue) {
|
||
|
||
// 使用指定的字节更新摘要
|
||
MessageDigest_MD5.update(plainText.getBytes());
|
||
MessageDigest_MD5.update(saltValue.getBytes());
|
||
|
||
// 获得密文
|
||
byte[] mdResult = MessageDigest_MD5.digest();
|
||
// 把密文转换成十六进制的字符串形式
|
||
return getHexString(hexDigitsLower, mdResult);
|
||
|
||
}
|
||
|
||
/**
|
||
* MD5加密后生成32位(小写字母+数字)字符串
|
||
* 同 MD5Lower() 一样
|
||
*/
|
||
public static String MD5(String plainText) {
|
||
return getMessageDigestString(plainText, hexDigitsLower, MessageDigest_MD5);
|
||
}
|
||
|
||
/**
|
||
* MD5加密后生成16位(小写字母+数字)字符串
|
||
* 同 MD5Lower() 一样
|
||
*/
|
||
public static String MD5_16(String plainText) {
|
||
return getMessageDigestString(plainText, hexDigitsLower, MessageDigest_MD5).substring(8, 24);
|
||
}
|
||
|
||
/**
|
||
* 校验MD5码
|
||
*
|
||
* @param text 要校验的字符串
|
||
* @param md5 md5值
|
||
* @return 校验结果
|
||
*/
|
||
public static boolean MD5valid(String text, String md5) throws Exception {
|
||
return md5.equals(MD5(text)) || md5.equals(MD5(text).toUpperCase());
|
||
}
|
||
|
||
/**
|
||
* 校验MD5码
|
||
*
|
||
* @param text 要校验的字符串
|
||
* @param md5 md5值
|
||
* @param salt 加密盐
|
||
* @return 校验结果
|
||
*/
|
||
public static boolean MD5valid(String text, String md5, String salt) {
|
||
return md5.equals(MD5Lower(text, salt)) || md5.equals(MD5Upper(text, salt).toUpperCase());
|
||
}
|
||
|
||
/**
|
||
* RSA2签名
|
||
*
|
||
* @param content 待签名的字符串
|
||
* @param privateKey rsa私钥字符串
|
||
* @param charset 字符集编码
|
||
* @return 签名结果
|
||
*/
|
||
public static String rsaSign(String content, String privateKey, String charset) throws Exception {
|
||
PrivateKey priKey = getPrivateKeyFromPKCS8(RSA, new ByteArrayInputStream(privateKey.getBytes()));
|
||
Signature_SHA256_RSA.initSign(priKey);
|
||
if (StringUtils.isBlank(charset)) {
|
||
Signature_SHA256_RSA.update(content.getBytes());
|
||
} else {
|
||
Signature_SHA256_RSA.update(content.getBytes(charset));
|
||
}
|
||
byte[] signed = Signature_SHA256_RSA.sign();
|
||
return new String(Base64.encode(signed));
|
||
}
|
||
|
||
/**
|
||
* RSA2验签
|
||
*
|
||
* @param content 被签名的内容
|
||
* @param sign 签名后的结果
|
||
* @param publicKey rsa公钥
|
||
* @param charset 字符集编码
|
||
* @return 验签结果
|
||
*/
|
||
public static boolean doCheck(String content, String sign, String publicKey, String charset) throws Exception {
|
||
PublicKey pubKey = getPublicKeyFromX509(RSA, new ByteArrayInputStream(publicKey.getBytes()));
|
||
Signature_SHA256_RSA.initVerify(pubKey);
|
||
Signature_SHA256_RSA.update(getContentBytes(content, charset));
|
||
return Signature_SHA256_RSA.verify(Base64.decode(sign));
|
||
}
|
||
|
||
/**
|
||
* 获取私钥对象
|
||
*
|
||
* @param algorithm 签名方式
|
||
* @param ins 私钥流
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
private static PrivateKey getPrivateKeyFromPKCS8(String algorithm, InputStream ins) throws Exception {
|
||
if (ins == null || StringUtils.isEmpty(algorithm)) {
|
||
return null;
|
||
}
|
||
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
|
||
byte[] encodedKey = readText(ins, UTF_8, true).getBytes();
|
||
encodedKey = Base64.decode(Arrays.toString(encodedKey));
|
||
return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
|
||
}
|
||
|
||
/**
|
||
* 获取公钥对象
|
||
*
|
||
* @param algorithm 签名方式
|
||
* @param ins 公钥流
|
||
* @return
|
||
* @throws Exception
|
||
*/
|
||
private static PublicKey getPublicKeyFromX509(String algorithm, InputStream ins) throws Exception {
|
||
KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
|
||
StringWriter writer = new StringWriter();
|
||
io(new InputStreamReader(ins), writer, true, true);
|
||
byte[] encodedKey = writer.toString().getBytes();
|
||
// 先base64解码
|
||
encodedKey = Base64.decode(Arrays.toString(encodedKey));
|
||
return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
|
||
}
|
||
|
||
/**
|
||
* 获取字符串对应编码的字节
|
||
*
|
||
* @param content 字符串内容
|
||
* @param charset 字符集编码
|
||
* @return
|
||
* @throws UnsupportedEncodingException
|
||
*/
|
||
private static byte[] getContentBytes(String content, String charset) throws UnsupportedEncodingException {
|
||
if (StringUtils.isEmpty(charset)) {
|
||
return content.getBytes();
|
||
}
|
||
return content.getBytes(charset);
|
||
}
|
||
|
||
/**
|
||
* 将指定输入流的所有文本全部读出到一个字符串中
|
||
*
|
||
* @param in 输入流
|
||
* @param charset 字符集编码
|
||
* @param closeIn 是否关闭流
|
||
* @return
|
||
* @throws IOException
|
||
*/
|
||
private static String readText(InputStream in, Charset charset, boolean closeIn) throws IOException {
|
||
Reader reader = charset == null ? new InputStreamReader(in) : new InputStreamReader(in, charset);
|
||
return readText(reader, closeIn);
|
||
}
|
||
|
||
/**
|
||
* 将指定<code>Reader</code>的所有文本全部读出到一个字符串中
|
||
*
|
||
* @param in 输入流
|
||
* @param closeIn 是否关闭流
|
||
* @return
|
||
* @throws IOException
|
||
*/
|
||
private static String readText(Reader in, boolean closeIn) throws IOException {
|
||
StringWriter out = new StringWriter();
|
||
io(in, out, closeIn, true);
|
||
return out.toString();
|
||
}
|
||
|
||
/**
|
||
* 从输入流读取内容,写入到输出流中
|
||
*
|
||
* @param in 输入流
|
||
* @param out 输出流
|
||
* @param closeIn 是否关闭流
|
||
* @param closeOut 是否关闭流
|
||
* @throws IOException
|
||
*/
|
||
private static void io(Reader in, Writer out, boolean closeIn, boolean closeOut) {
|
||
int bufferSize = 8192 >> 1;
|
||
char[] buffer = new char[bufferSize];
|
||
int amount;
|
||
try {
|
||
while ((amount = in.read(buffer)) >= 0) {
|
||
out.write(buffer, 0, amount);
|
||
}
|
||
out.flush();
|
||
} catch (Exception e) {
|
||
logger.error("从输入流读取内容,写入到输出流中异常:{}", e.getMessage(), e);
|
||
} finally {
|
||
if (closeIn) {
|
||
try {
|
||
in.close();
|
||
} catch (IOException e) {
|
||
logger.error("从输入流读取内容,写入到输出流中异常:{}", e.getMessage(), e);
|
||
}
|
||
}
|
||
if (closeOut) {
|
||
try {
|
||
out.close();
|
||
} catch (IOException e) {
|
||
logger.error("从输入流读取内容,写入到输出流中异常:{}", e.getMessage(), e);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private static String getMessageDigestString(String str, char[] hexDigits, MessageDigest messageDigest) {
|
||
messageDigest.update(str.getBytes(UTF_8));
|
||
|
||
byte[] md = messageDigest.digest();
|
||
return getHexString(hexDigits, md);
|
||
}
|
||
|
||
private static String getHexString(char[] hexDigits, byte[] md) {
|
||
int j = md.length;
|
||
char[] buf = new char[j * 2];
|
||
int k = 0;
|
||
for (byte byteO : md) {
|
||
buf[k++] = hexDigits[byteO >>> 4 & 0xf];
|
||
buf[k++] = hexDigits[byteO & 0xf];
|
||
}
|
||
return new String(buf);
|
||
}
|
||
}
|
||
|