package com.xiaoleilu.hutool.crypto;
import java.io.File;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.UUID;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import com.xiaoleilu.hutool.crypto.asymmetric.AsymmetricAlgorithm;
import com.xiaoleilu.hutool.crypto.asymmetric.DSA;
import com.xiaoleilu.hutool.crypto.asymmetric.RSA;
import com.xiaoleilu.hutool.crypto.digest.DigestAlgorithm;
import com.xiaoleilu.hutool.crypto.digest.Digester;
import com.xiaoleilu.hutool.crypto.digest.HMac;
import com.xiaoleilu.hutool.crypto.digest.HmacAlgorithm;
import com.xiaoleilu.hutool.crypto.symmetric.SymmetricAlgorithm;
import com.xiaoleilu.hutool.crypto.symmetric.SymmetricCrypto;
import com.xiaoleilu.hutool.io.FileUtil;
import com.xiaoleilu.hutool.lang.Assert;
import com.xiaoleilu.hutool.util.CharsetUtil;
import com.xiaoleilu.hutool.util.RandomUtil;
import com.xiaoleilu.hutool.util.StrUtil;
/**
* 安全相关工具类<br>
* 加密分为三种:<br>
* 1、对称加密(symmetric),例如:AES、DES等<br>
* 2、非对称加密(asymmetric),例如:RSA、DSA等<br>
* 3、摘要加密(digest),例如:MD5、SHA-1、SHA-256、HMAC等<br>
*
* @author xiaoleilu
*
*/
public final class SecureUtil {
private SecureUtil() {}
/**
* 默认密钥字节数
*
* <pre>
* RSA/DSA
* Default Keysize 1024
* Keysize must be a multiple of 64, ranging from 512 to 1024 (inclusive).
* </pre>
*/
public static final int DEFAULT_KEY_SIZE = 1024;
/**
* 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
*
* @param algorithm 算法,支持PBE算法
* @return {@link SecretKey}
*/
public static SecretKey generateKey(String algorithm) {
SecretKey secretKey;
try {
secretKey = KeyGenerator.getInstance(algorithm).generateKey();
} catch (NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
return secretKey;
}
/**
* 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
*
* @param algorithm 算法
* @param key 密钥
* @return {@link SecretKey}
*/
public static SecretKey generateKey(String algorithm, byte[] key) {
Assert.notBlank(algorithm, "Algorithm is blank!");
SecretKey secretKey = null;
if (algorithm.startsWith("PBE")) {
// PBE密钥
secretKey = generatePBEKey(algorithm, (null == key) ? null : StrUtil.str(key, CharsetUtil.CHARSET_UTF_8).toCharArray());
} else if (algorithm.startsWith("DES")) {
// DES密钥
secretKey = generateDESKey(algorithm, key);
} else {
// 其它算法密钥
secretKey = (null == key) ? generateKey(algorithm) : new SecretKeySpec(key, algorithm);
}
return secretKey;
}
/**
* 生成 {@link SecretKey}
*
* @param algorithm DES算法,包括DES、DESede等
* @param key 密钥
* @return {@link SecretKey}
*/
public static SecretKey generateDESKey(String algorithm, byte[] key) {
if (StrUtil.isBlank(algorithm) || false == algorithm.startsWith("DES")) {
throw new CryptoException("Algorithm [{}] is not a DES algorithm!");
}
SecretKey secretKey = null;
if (null == key) {
secretKey = generateKey(algorithm);
} else {
DESKeySpec keySpec;
try {
keySpec = new DESKeySpec(key);
} catch (InvalidKeyException e) {
throw new CryptoException(e);
}
secretKey = generateKey(algorithm, keySpec);
}
return secretKey;
}
/**
* 生成PBE {@link SecretKey}
*
* @param algorithm PBE算法,包括:PBEWithMD5AndDES、PBEWithSHA1AndDESede、PBEWithSHA1AndRC2_40等
* @param key 密钥
* @return {@link SecretKey}
*/
public static SecretKey generatePBEKey(String algorithm, char[] key) {
if (StrUtil.isBlank(algorithm) || false == algorithm.startsWith("PBE")) {
throw new CryptoException("Algorithm [{}] is not a PBE algorithm!");
}
if (null == key) {
key = RandomUtil.randomString(32).toCharArray();
}
PBEKeySpec keySpec = new PBEKeySpec(key);
return generateKey(algorithm, keySpec);
}
/**
* 生成 {@link SecretKey},仅用于对称加密和摘要算法
*
* @param algorithm 算法
* @param keySpec {@link KeySpec}
* @return {@link SecretKey}
*/
public static SecretKey generateKey(String algorithm, KeySpec keySpec) {
try {
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
return keyFactory.generateSecret(keySpec);
} catch (Exception e) {
throw new CryptoException(e);
}
}
/**
* 生成私钥,仅用于非对称加密
*
* @param algorithm 算法
* @param key 密钥
* @return 私钥 {@link PrivateKey}
*/
public static PrivateKey generatePrivateKey(String algorithm, byte[] key) {
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(key);
try {
return KeyFactory.getInstance(algorithm).generatePrivate(pkcs8KeySpec);
} catch (Exception e) {
throw new CryptoException(e);
}
}
/**
* 生成私钥,仅用于非对称加密
*
* @param keyStore {@link KeyStore}
* @param alias 别名
* @param password 密码
* @return 私钥 {@link PrivateKey}
*/
public static PrivateKey generatePrivateKey(KeyStore keyStore, String alias, char[] password) {
try {
return (PrivateKey) keyStore.getKey(alias, password);
} catch (Exception e) {
throw new CryptoException(e);
}
}
/**
* 生成公钥,仅用于非对称加密
*
* @param algorithm 算法
* @param key 密钥
* @return 公钥 {@link PublicKey}
*/
public static PublicKey generatePublicKey(String algorithm, byte[] key) {
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(key);
try {
return KeyFactory.getInstance(algorithm).generatePublic(x509KeySpec);
} catch (Exception e) {
throw new CryptoException(e);
}
}
/**
* 生成用于非对称加密的公钥和私钥,仅用于非对称加密
*
* @param algorithm 非对称加密算法
* @return {@link KeyPair}
*/
public static KeyPair generateKeyPair(String algorithm) {
return generateKeyPair(algorithm, DEFAULT_KEY_SIZE, null);
}
/**
* 生成用于非对称加密的公钥和私钥
*
* @param algorithm 非对称加密算法
* @param keySize 密钥模(modulus )长度
* @return {@link KeyPair}
*/
public static KeyPair generateKeyPair(String algorithm, int keySize) {
return generateKeyPair(algorithm, keySize, null);
}
/**
* 生成用于非对称加密的公钥和私钥
*
* @param algorithm 非对称加密算法
* @param keySize 密钥模(modulus )长度
* @param seed 种子
* @return {@link KeyPair}
*/
public static KeyPair generateKeyPair(String algorithm, int keySize, byte[] seed) {
KeyPairGenerator keyPairGen;
try {
keyPairGen = KeyPairGenerator.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
if(keySize <= 0){
keySize = DEFAULT_KEY_SIZE;
}
if (null != seed) {
SecureRandom random = new SecureRandom(seed);
keyPairGen.initialize(keySize, random);
} else {
keyPairGen.initialize(keySize);
}
return keyPairGen.generateKeyPair();
}
/**
* 生成签名对象,仅用于非对称加密
*
* @param asymmetricAlgorithm {@link AsymmetricAlgorithm} 非对称加密算法
* @param digestAlgorithm {@link DigestAlgorithm} 摘要算法
* @return {@link Signature}
*/
public static Signature generateSignature(AsymmetricAlgorithm asymmetricAlgorithm, DigestAlgorithm digestAlgorithm) {
String digestPart = (null == digestAlgorithm) ? "NONE" : digestAlgorithm.name();
String algorithm = StrUtil.format("{}with{}", digestPart, asymmetricAlgorithm.getValue());
try {
return Signature.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
}
/**
* 读取密钥库(Java Key Store,JKS) KeyStore文件<br>
* KeyStore文件用于数字证书的密钥对保存<br>
* see: http://snowolf.iteye.com/blog/391931
*
* @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
* @param password 密码
* @return {@link KeyStore}
*/
public static KeyStore readJKSKeyStore(InputStream in, char[] password){
return readKeyStore("JKS", in, password);
}
/**
* 读取KeyStore文件<br>
* KeyStore文件用于数字证书的密钥对保存<br>
* see: http://snowolf.iteye.com/blog/391931
*
* @param type 类型
* @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
* @param password 密码
* @return {@link KeyStore}
*/
public static KeyStore readKeyStore(String type, InputStream in, char[] password){
KeyStore keyStore = null;
try {
keyStore = KeyStore.getInstance(type);
keyStore.load(in, password);
} catch (Exception e) {
throw new CryptoException(e);
}
return keyStore;
}
/**
* 读取X.509 Certification文件<br>
* Certification为证书文件<br>
* see: http://snowolf.iteye.com/blog/391931
*
* @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
* @param password 密码
* @return {@link KeyStore}
*/
public static Certificate readX509Certificate(InputStream in, char[] password){
return readCertificate("X.509", in, password);
}
/**
* 读取Certification文件<br>
* Certification为证书文件<br>
* see: http://snowolf.iteye.com/blog/391931
*
* @param type 类型
* @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
* @param password 密码
* @return {@link KeyStore}
*/
public static Certificate readCertificate(String type, InputStream in, char[] password){
Certificate certificate;
try {
certificate = CertificateFactory.getInstance(type).generateCertificate(in);
} catch (Exception e) {
throw new CryptoException(e);
}
return certificate;
}
/**
* 获得 Certification
* @param keyStore {@link KeyStore}
* @param alias 别名
* @return {@link Certificate}
*/
public static Certificate getCertificate(KeyStore keyStore, String alias){
try {
return keyStore.getCertificate(alias);
} catch (Exception e) {
throw new CryptoException(e);
}
}
// ------------------------------------------------------------------- 对称加密算法
/**
* AES加密,生成随机KEY。注意解密时必须使用相同 {@link SymmetricCrypto}对象或者使用相同KEY<br>
* 例:<br>
* AES加密:aes().encrypt(data)<br>
* AES解密:aes().decrypt(data)<br>
*
* @return {@link SymmetricCrypto}
*/
public static SymmetricCrypto aes() {
return new SymmetricCrypto(SymmetricAlgorithm.AES);
}
/**
* AES加密<br>
* 例:<br>
* AES加密:aes(key).encrypt(data)<br>
* AES解密:aes(key).decrypt(data)<br>
*
* @param key 密钥
* @return {@link SymmetricCrypto}
*/
public static SymmetricCrypto aes(byte[] key) {
return new SymmetricCrypto(SymmetricAlgorithm.AES, key);
}
/**
* DES加密,生成随机KEY。注意解密时必须使用相同 {@link SymmetricCrypto}对象或者使用相同KEY<br>
* 例:<br>
* DES加密:des().encrypt(data)<br>
* DES解密:des().decrypt(data)<br>
*
* @return {@link SymmetricCrypto}
*/
public static SymmetricCrypto des() {
return new SymmetricCrypto(SymmetricAlgorithm.DES);
}
/**
* DES加密<br>
* 例:<br>
* DES加密:des(key).encrypt(data)<br>
* DES解密:des(key).decrypt(data)<br>
*
* @param key 密钥
* @return {@link SymmetricCrypto}
*/
public static SymmetricCrypto des(byte[] key) {
return new SymmetricCrypto(SymmetricAlgorithm.DES, key);
}
// ------------------------------------------------------------------- 摘要算法
/**
* MD5加密<br>
* 例:<br>
* MD5加密:md5().digest(data)<br>
* MD5加密并转为16进制字符串:md5().digestHex(data)<br>
*
* @return {@link Digester}
*/
public static Digester md5() {
return new Digester(DigestAlgorithm.MD5);
}
/**
* MD5加密,生成16进制MD5字符串<br>
* @return MD5字符串
*/
public static String md5(String data) {
return new Digester(DigestAlgorithm.MD5).digestHex(data);
}
/**
* MD5加密,生成16进制MD5字符串<br>
* @return MD5字符串
*/
public static String md5(InputStream data) {
return new Digester(DigestAlgorithm.MD5).digestHex(data);
}
/**
* MD5加密文件,生成16进制MD5字符串<br>
* @return MD5字符串
*/
public static String md5(File dataFile) {
return new Digester(DigestAlgorithm.MD5).digestHex(dataFile);
}
/**
* SHA1加密<br>
* 例:<br>
* SHA1加密:sha1().digest(data)<br>
* SHA1加密并转为16进制字符串:sha1().digestHex(data)<br>
*
* @return {@link Digester}
*/
public static Digester sha1() {
return new Digester(DigestAlgorithm.SHA1);
}
/**
* SHA1加密,生成16进制SHA1字符串<br>
* @return SHA1字符串
*/
public static String sha1(String data) {
return new Digester(DigestAlgorithm.SHA1).digestHex(data);
}
/**
* SHA1加密,生成16进制SHA1字符串<br>
* @return SHA1字符串
*/
public static String sha1(InputStream data) {
return new Digester(DigestAlgorithm.SHA1).digestHex(data);
}
/**
* SHA1加密文件,生成16进制SHA1字符串<br>
* @return SHA1字符串
*/
public static String sha1(File dataFile) {
return new Digester(DigestAlgorithm.SHA1).digestHex(dataFile);
}
/**
* 创建HMac对象,调用digest方法可获得hmac值
* @param algorithm {@link HmacAlgorithm}
* @param key 密钥,如果为<code>null</code>生成随机密钥
* @return {@link HMac}
* @since 3.0.3
*/
public static HMac hmac(HmacAlgorithm algorithm, byte[] key){
return new HMac(algorithm, key);
}
/**
* 创建HMac对象,调用digest方法可获得hmac值
* @param algorithm {@link HmacAlgorithm}
* @param key 密钥{@link SecretKey},如果为<code>null</code>生成随机密钥
* @return {@link HMac}
* @since 3.0.3
*/
public static HMac hmac(HmacAlgorithm algorithm, SecretKey key){
return new HMac(algorithm, key);
}
/**
* HmacMD5加密器<br>
* 例:<br>
* HmacMD5加密:hmacMd5(key).digest(data)<br>
* HmacMD5加密并转为16进制字符串:hmacMd5(key).digestHex(data)<br>
* @param key 加密密钥
* @return {@link HMac}
*/
public static HMac hmacMd5(byte[] key){
return new HMac(HmacAlgorithm.HmacMD5, key);
}
/**
* HmacMD5加密器,生成随机KEY<br>
* 例:<br>
* HmacMD5加密:hmacMd5().digest(data)<br>
* HmacMD5加密并转为16进制字符串:hmacMd5().digestHex(data)<br>
* @return {@link HMac}
*/
public static HMac hmacMd5(){
return new HMac(HmacAlgorithm.HmacMD5);
}
/**
* HmacSHA1加密器<br>
* 例:<br>
* HmacSHA1加密:hmacSha1(key).digest(data)<br>
* HmacSHA1加密并转为16进制字符串:hmacSha1(key).digestHex(data)<br>
* @param key 加密密钥
* @return {@link HMac}
*/
public static HMac hmacSha1(byte[] key){
return new HMac(HmacAlgorithm.HmacSHA1, key);
}
/**
* HmacSHA1加密器,生成随机KEY<br>
* 例:<br>
* HmacSHA1加密:hmacSha1().digest(data)<br>
* HmacSHA1加密并转为16进制字符串:hmacSha1().digestHex(data)<br>
* @return {@link HMac}
*/
public static HMac hmacSha1(){
return new HMac(HmacAlgorithm.HmacSHA1);
}
// ------------------------------------------------------------------- 非称加密算法
/**
* 创建RSA算法对象<br>
* 生成新的私钥公钥对
* @return {@link RSA}
* @since 3.0.5
*/
public static RSA rsa(){
return new RSA();
}
/**
* 创建RSA算法对象<br>
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
*
* @param privateKeyBase64 私钥Base64
* @param publicKeyBase64 公钥Base64
* @since 3.0.5
*/
public static RSA rsa(String privateKeyBase64, String publicKeyBase64){
return new RSA(privateKeyBase64, publicKeyBase64);
}
/**
* 创建RSA算法对象<br>
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
*
* @param privateKey 私钥
* @param publicKey 公钥
* @since 3.0.5
*/
public static RSA rsa(byte[] privateKey, byte[] publicKey){
return new RSA(privateKey, privateKey);
}
/**
* 创建RSA算法对象<br>
* 生成新的私钥公钥对
* @return {@link DSA}
* @since 3.0.5
*/
public static DSA dsa(){
return new DSA();
}
/**
* 创建DSA算法对象<br>
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
*
* @param privateKeyBase64 私钥Base64
* @param publicKeyBase64 公钥Base64
* @since 3.0.5
*/
public static DSA dsa(String privateKeyBase64, String publicKeyBase64){
return new DSA(privateKeyBase64, publicKeyBase64);
}
/**
* 创建DSA算法对象<br>
* 私钥和公钥同时为空时生成一对新的私钥和公钥<br>
* 私钥和公钥可以单独传入一个,如此则只能使用此钥匙来做加密或者解密
*
* @param privateKey 私钥
* @param publicKey 公钥
* @since 3.0.5
*/
public static DSA dsa(byte[] privateKey, byte[] publicKey){
return new DSA(privateKey, privateKey);
}
// ------------------------------------------------------------------- UUID
/**
* @return 简化的UUID,去掉了横线
*/
public static String simpleUUID() {
return UUID.randomUUID().toString().replace("-", "");
}
}