diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CertUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CertUtil.java
new file mode 100644
index 000000000..e93fdb8ea
--- /dev/null
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/CertUtil.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.crypto;
+
+import org.dromara.hutool.core.io.file.FileUtil;
+import org.dromara.hutool.crypto.provider.GlobalProviderFactory;
+
+import java.io.File;
+import java.io.InputStream;
+import java.security.KeyPairGenerator;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Provider;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+
+/**
+ * 数字证书{@link Certificate}相关工具类
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class CertUtil {
+
+ /**
+ * Certification类型:X.509
+ */
+ public static final String TYPE_X509 = "X.509";
+
+ /**
+ * 读取X.509 Certification文件
+ * Certification为证书文件
+ * see: ...
+ *
+ * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
+ * @return {@link KeyStore}
+ */
+ public static Certificate readX509Certificate(final InputStream in) {
+ return readCertificate(TYPE_X509, in);
+ }
+
+ /**
+ * 读取X.509 Certification文件
+ * Certification为证书文件
+ * see: ...
+ *
+ * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
+ * @param password 密码
+ * @param alias 别名
+ * @return {@link KeyStore}
+ */
+ public static Certificate readX509Certificate(final InputStream in, final char[] password, final String alias) {
+ return readCertificate(TYPE_X509, in, password, alias);
+ }
+
+ /**
+ * 读取Certification文件
+ * Certification为证书文件
+ * see: ...
+ *
+ * @param type 类型,例如X.509
+ * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
+ * @param password 密码
+ * @param alias 别名
+ * @return {@link KeyStore}
+ * @since 4.4.1
+ */
+ public static Certificate readCertificate(final String type, final InputStream in, final char[] password, final String alias) {
+ final KeyStore keyStore = KeyStoreUtil.readKeyStore(type, in, password);
+ try {
+ return keyStore.getCertificate(alias);
+ } catch (final KeyStoreException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 读取Certification文件
+ * Certification为证书文件
+ * see: ...
+ *
+ * @param type 类型,例如X.509
+ * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
+ * @return {@link Certificate}
+ */
+ public static Certificate readCertificate(final String type, final InputStream in) {
+ try {
+ return getCertificateFactory(type).generateCertificate(in);
+ } catch (final CertificateException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 获得 Certification
+ *
+ * @param keyStore {@link KeyStore}
+ * @param alias 别名
+ * @return {@link Certificate}
+ */
+ public static Certificate getCertificate(final KeyStore keyStore, final String alias) {
+ try {
+ return keyStore.getCertificate(alias);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 获取{@link CertificateFactory}
+ *
+ * @param type 类型,例如X.509
+ * @return {@link KeyPairGenerator}
+ * @since 4.5.0
+ */
+ public static CertificateFactory getCertificateFactory(final String type) {
+ final Provider provider = GlobalProviderFactory.getProvider();
+
+ final CertificateFactory factory;
+ try {
+ factory = (null == provider) ? CertificateFactory.getInstance(type) : CertificateFactory.getInstance(type, provider);
+ } catch (final CertificateException e) {
+ throw new CryptoException(e);
+ }
+ return factory;
+ }
+}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyStoreUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyStoreUtil.java
new file mode 100644
index 000000000..b02408faf
--- /dev/null
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyStoreUtil.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.crypto;
+
+import org.dromara.hutool.core.io.IoUtil;
+import org.dromara.hutool.core.io.file.FileUtil;
+import org.dromara.hutool.crypto.provider.GlobalProviderFactory;
+
+import java.io.File;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.Provider;
+
+/**
+ * {@link KeyStore} 相关工具类
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class KeyStoreUtil {
+
+ /**
+ * Java密钥库(Java Key Store,JKS)KEY_STORE
+ */
+ public static final String TYPE_JKS = "JKS";
+ /**
+ * jceks
+ */
+ public static final String TYPE_JCEKS = "jceks";
+ /**
+ * PKCS12是公钥加密标准,它规定了可包含所有私钥、公钥和证书。其以二进制格式存储,也称为 PFX 文件
+ */
+ public static final String TYPE_PKCS12 = "pkcs12";
+
+ /**
+ * 读取密钥库(Java Key Store,JKS) KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ * see: ...
+ *
+ * @param keyFile 证书文件
+ * @param password 密码
+ * @return {@link KeyStore}
+ * @since 5.0.0
+ */
+ public static KeyStore readJKSKeyStore(final File keyFile, final char[] password) {
+ return readKeyStore(TYPE_JKS, keyFile, password);
+ }
+
+ /**
+ * 读取密钥库(Java Key Store,JKS) KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ * see: ...
+ *
+ * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(File)} 读取
+ * @param password 密码
+ * @return {@link KeyStore}
+ */
+ public static KeyStore readJKSKeyStore(final InputStream in, final char[] password) {
+ return readKeyStore(TYPE_JKS, in, password);
+ }
+
+ /**
+ * 读取PKCS12 KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ *
+ * @param keyFile 证书文件
+ * @param password 密码
+ * @return {@link KeyStore}
+ * @since 5.0.0
+ */
+ public static KeyStore readPKCS12KeyStore(final File keyFile, final char[] password) {
+ return readKeyStore(TYPE_PKCS12, keyFile, password);
+ }
+
+ /**
+ * 读取PKCS12 KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ *
+ * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
+ * @param password 密码
+ * @return {@link KeyStore}
+ * @since 5.0.0
+ */
+ public static KeyStore readPKCS12KeyStore(final InputStream in, final char[] password) {
+ return readKeyStore(TYPE_PKCS12, in, password);
+ }
+
+ /**
+ * 读取KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ * see: ...
+ *
+ * @param type 类型
+ * @param keyFile 证书文件
+ * @param password 密码,null表示无密码
+ * @return {@link KeyStore}
+ * @since 5.0.0
+ */
+ public static KeyStore readKeyStore(final String type, final File keyFile, final char[] password) {
+ InputStream in = null;
+ try {
+ in = FileUtil.getInputStream(keyFile);
+ return readKeyStore(type, in, password);
+ } finally {
+ IoUtil.closeQuietly(in);
+ }
+ }
+
+ /**
+ * 读取KeyStore文件
+ * KeyStore文件用于数字证书的密钥对保存
+ * see: ...
+ *
+ * @param type 类型
+ * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(File)} 读取
+ * @param password 密码,null表示无密码
+ * @return {@link KeyStore}
+ */
+ public static KeyStore readKeyStore(final String type, final InputStream in, final char[] password) {
+ final KeyStore keyStore = getKeyStore(type);
+ try {
+ keyStore.load(in, password);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
+ return keyStore;
+ }
+
+ /**
+ * 获取{@link KeyStore}对象
+ *
+ * @param type 类型
+ * @return {@link KeyStore}
+ */
+ public static KeyStore getKeyStore(final String type) {
+ final Provider provider = GlobalProviderFactory.getProvider();
+ try {
+ return null == provider ? KeyStore.getInstance(type) : KeyStore.getInstance(type, provider);
+ } catch (final KeyStoreException e) {
+ throw new CryptoException(e);
+ }
+ }
+}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java
index 10225050c..7f49f91a1 100644
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/KeyUtil.java
@@ -12,15 +12,13 @@
package org.dromara.hutool.crypto;
+import org.dromara.hutool.core.array.ArrayUtil;
import org.dromara.hutool.core.codec.binary.Base64;
import org.dromara.hutool.core.io.file.FileUtil;
-import org.dromara.hutool.core.io.IoUtil;
import org.dromara.hutool.core.lang.Assert;
-import org.dromara.hutool.core.array.ArrayUtil;
-import org.dromara.hutool.core.lang.Console;
import org.dromara.hutool.core.text.CharUtil;
-import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.core.text.StrUtil;
+import org.dromara.hutool.core.util.RandomUtil;
import org.dromara.hutool.crypto.asymmetric.AsymmetricAlgorithm;
import org.dromara.hutool.crypto.bc.BCUtil;
import org.dromara.hutool.crypto.bc.SmUtil;
@@ -30,37 +28,14 @@ import org.dromara.hutool.crypto.symmetric.SymmetricAlgorithm;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.DESKeySpec;
-import javax.crypto.spec.DESedeKeySpec;
-import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.InputStream;
import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.Provider;
-import java.security.PublicKey;
-import java.security.SecureRandom;
+import java.security.*;
import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPrivateCrtKey;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.ECGenParameterSpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.X509EncodedKeySpec;
+import java.security.spec.*;
/**
* 密钥工具类
@@ -77,23 +52,6 @@ import java.security.spec.X509EncodedKeySpec;
*/
public class KeyUtil {
- /**
- * Java密钥库(Java Key Store,JKS)KEY_STORE
- */
- public static final String KEY_TYPE_JKS = "JKS";
- /**
- * jceks
- */
- public static final String KEY_TYPE_JCEKS = "jceks";
- /**
- * PKCS12是公钥加密标准,它规定了可包含所有私钥、公钥和证书。其以二进制格式存储,也称为 PFX 文件
- */
- public static final String KEY_TYPE_PKCS12 = "pkcs12";
- /**
- * Certification类型:X.509
- */
- public static final String CERT_TYPE_X509 = "X.509";
-
/**
* 默认密钥字节数
*
@@ -105,15 +63,7 @@ public class KeyUtil {
*/
public static final int DEFAULT_KEY_SIZE = 1024;
- /**
- * SM2默认曲线
- *
- *
- * Default SM2 curve
- *
- */
- public static final String SM2_DEFAULT_CURVE = SmUtil.SM2_CURVE_NAME;
-
+ // region ----- generateKey
/**
* 生成 {@link SecretKey},仅用于对称加密和摘要算法密钥生成
*
@@ -205,18 +155,8 @@ public class KeyUtil {
if (null == key) {
secretKey = generateKey(algorithm);
} else {
- final KeySpec keySpec;
- try {
- if (algorithm.startsWith("DESede")) {
- // DESede兼容
- keySpec = new DESedeKeySpec(key);
- } else {
- keySpec = new DESKeySpec(key);
- }
- } catch (final InvalidKeyException e) {
- throw new CryptoException(e);
- }
- secretKey = generateKey(algorithm, keySpec);
+ secretKey = generateKey(algorithm,
+ SpecUtil.createKeySpec(algorithm, key));
}
return secretKey;
}
@@ -225,19 +165,18 @@ public class KeyUtil {
* 生成PBE {@link SecretKey}
*
* @param algorithm PBE算法,包括:PBEWithMD5AndDES、PBEWithSHA1AndDESede、PBEWithSHA1AndRC2_40等
- * @param key 密钥
+ * @param password 口令
* @return {@link SecretKey}
*/
- public static SecretKey generatePBEKey(final String algorithm, char[] key) {
+ public static SecretKey generatePBEKey(final String algorithm, char[] password) {
if (StrUtil.isBlank(algorithm) || !algorithm.startsWith("PBE")) {
throw new CryptoException("Algorithm [{}] is not a PBE algorithm!", algorithm);
}
- if (null == key) {
- key = RandomUtil.randomString(32).toCharArray();
+ if (null == password) {
+ password = RandomUtil.randomString(32).toCharArray();
}
- final PBEKeySpec keySpec = new PBEKeySpec(key);
- return generateKey(algorithm, keySpec);
+ return generateKey(algorithm, SpecUtil.createPBEKeySpec(password));
}
/**
@@ -255,7 +194,9 @@ public class KeyUtil {
throw new CryptoException(e);
}
}
+ // endregion
+ // region ----- keyPair
/**
* 生成RSA私钥,仅用于非对称加密
* 采用PKCS#8规范,此规范定义了私钥信息语法和加密私钥语法
@@ -372,6 +313,51 @@ public class KeyUtil {
}
}
+ /**
+ * 通过RSA私钥生成RSA公钥
+ *
+ * @param privateKey RSA私钥
+ * @return RSA公钥,null表示私钥不被支持
+ * @since 5.3.6
+ */
+ public static PublicKey getRSAPublicKey(final PrivateKey privateKey) {
+ if (privateKey instanceof RSAPrivateCrtKey) {
+ final RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey;
+ return getRSAPublicKey(privk.getModulus(), privk.getPublicExponent());
+ }
+ return null;
+ }
+
+ /**
+ * 获得RSA公钥对象
+ *
+ * @param modulus Modulus
+ * @param publicExponent Public Exponent
+ * @return 公钥
+ * @since 5.3.6
+ */
+ public static PublicKey getRSAPublicKey(final String modulus, final String publicExponent) {
+ return getRSAPublicKey(
+ new BigInteger(modulus, 16), new BigInteger(publicExponent, 16));
+ }
+
+ /**
+ * 获得RSA公钥对象
+ *
+ * @param modulus Modulus
+ * @param publicExponent Public Exponent
+ * @return 公钥
+ * @since 5.3.6
+ */
+ public static PublicKey getRSAPublicKey(final BigInteger modulus, final BigInteger publicExponent) {
+ final RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
+ try {
+ return getKeyFactory(AsymmetricAlgorithm.RSA.getValue()).generatePublic(publicKeySpec);
+ } catch (final InvalidKeySpecException e) {
+ throw new CryptoException(e);
+ }
+ }
+
/**
* 生成用于非对称加密的公钥和私钥,仅用于非对称加密
* 密钥对生成算法见:...
@@ -413,7 +399,7 @@ public class KeyUtil {
public static KeyPair generateKeyPair(final String algorithm, final int keySize, final byte[] seed) {
// SM2算法需要单独定义其曲线生成
if ("SM2".equalsIgnoreCase(algorithm)) {
- final ECGenParameterSpec sm2p256v1 = new ECGenParameterSpec(SM2_DEFAULT_CURVE);
+ final ECGenParameterSpec sm2p256v1 = new ECGenParameterSpec(SmUtil.SM2_CURVE_NAME);
return generateKeyPair(algorithm, keySize, seed, sm2p256v1);
}
@@ -549,6 +535,42 @@ public class KeyUtil {
return keyPairGen.generateKeyPair();
}
+ /**
+ * 从KeyStore中获取私钥公钥
+ *
+ * @param type 类型
+ * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
+ * @param password 密码
+ * @param alias 别名
+ * @return {@link KeyPair}
+ * @since 4.4.1
+ */
+ public static KeyPair getKeyPair(final String type, final InputStream in, final char[] password, final String alias) {
+ final KeyStore keyStore = KeyStoreUtil.readKeyStore(type, in, password);
+ return getKeyPair(keyStore, password, alias);
+ }
+
+ /**
+ * 从KeyStore中获取私钥公钥
+ *
+ * @param keyStore {@link KeyStore}
+ * @param password 密码
+ * @param alias 别名
+ * @return {@link KeyPair}
+ * @since 4.4.1
+ */
+ public static KeyPair getKeyPair(final KeyStore keyStore, final char[] password, final String alias) {
+ final PublicKey publicKey;
+ final PrivateKey privateKey;
+ try {
+ publicKey = keyStore.getCertificate(alias).getPublicKey();
+ privateKey = (PrivateKey) keyStore.getKey(alias, password);
+ } catch (final Exception e) {
+ throw new CryptoException(e);
+ }
+ return new KeyPair(publicKey, privateKey);
+ }
+
/**
* 获取{@link KeyPairGenerator}
*
@@ -562,13 +584,14 @@ public class KeyUtil {
final KeyPairGenerator keyPairGen;
try {
keyPairGen = (null == provider) //
- ? KeyPairGenerator.getInstance(getMainAlgorithm(algorithm)) //
- : KeyPairGenerator.getInstance(getMainAlgorithm(algorithm), provider);//
+ ? KeyPairGenerator.getInstance(getMainAlgorithm(algorithm)) //
+ : KeyPairGenerator.getInstance(getMainAlgorithm(algorithm), provider);//
} catch (final NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
return keyPairGen;
}
+ // endregion
/**
* 获取{@link KeyFactory}
@@ -583,8 +606,8 @@ public class KeyUtil {
final KeyFactory keyFactory;
try {
keyFactory = (null == provider) //
- ? KeyFactory.getInstance(getMainAlgorithm(algorithm)) //
- : KeyFactory.getInstance(getMainAlgorithm(algorithm), provider);
+ ? KeyFactory.getInstance(getMainAlgorithm(algorithm)) //
+ : KeyFactory.getInstance(getMainAlgorithm(algorithm), provider);
} catch (final NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
@@ -604,8 +627,8 @@ public class KeyUtil {
final SecretKeyFactory keyFactory;
try {
keyFactory = (null == provider) //
- ? SecretKeyFactory.getInstance(getMainAlgorithm(algorithm)) //
- : SecretKeyFactory.getInstance(getMainAlgorithm(algorithm), provider);
+ ? SecretKeyFactory.getInstance(getMainAlgorithm(algorithm)) //
+ : SecretKeyFactory.getInstance(getMainAlgorithm(algorithm), provider);
} catch (final NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
@@ -624,8 +647,8 @@ public class KeyUtil {
final KeyGenerator generator;
try {
generator = (null == provider) //
- ? KeyGenerator.getInstance(getMainAlgorithm(algorithm)) //
- : KeyGenerator.getInstance(getMainAlgorithm(algorithm), provider);
+ ? KeyGenerator.getInstance(getMainAlgorithm(algorithm)) //
+ : KeyGenerator.getInstance(getMainAlgorithm(algorithm), provider);
} catch (final NoSuchAlgorithmException e) {
throw new CryptoException(e);
}
@@ -667,174 +690,14 @@ public class KeyUtil {
algorithm = StrUtil.subSuf(algorithm, indexOfWith + "with".length());
}
if ("ECDSA".equalsIgnoreCase(algorithm)
- || "SM2".equalsIgnoreCase(algorithm)
- || "ECIES".equalsIgnoreCase(algorithm)
+ || "SM2".equalsIgnoreCase(algorithm)
+ || "ECIES".equalsIgnoreCase(algorithm)
) {
algorithm = "EC";
}
return algorithm;
}
- /**
- * 读取密钥库(Java Key Store,JKS) KeyStore文件
- * KeyStore文件用于数字证书的密钥对保存
- * see: ...
- *
- * @param keyFile 证书文件
- * @param password 密码
- * @return {@link KeyStore}
- * @since 5.0.0
- */
- public static KeyStore readJKSKeyStore(final File keyFile, final char[] password) {
- return readKeyStore(KEY_TYPE_JKS, keyFile, password);
- }
-
- /**
- * 读取密钥库(Java Key Store,JKS) KeyStore文件
- * KeyStore文件用于数字证书的密钥对保存
- * see: ...
- *
- * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(File)} 读取
- * @param password 密码
- * @return {@link KeyStore}
- */
- public static KeyStore readJKSKeyStore(final InputStream in, final char[] password) {
- return readKeyStore(KEY_TYPE_JKS, in, password);
- }
-
- /**
- * 读取PKCS12 KeyStore文件
- * KeyStore文件用于数字证书的密钥对保存
- *
- * @param keyFile 证书文件
- * @param password 密码
- * @return {@link KeyStore}
- * @since 5.0.0
- */
- public static KeyStore readPKCS12KeyStore(final File keyFile, final char[] password) {
- return readKeyStore(KEY_TYPE_PKCS12, keyFile, password);
- }
-
- /**
- * 读取PKCS12 KeyStore文件
- * KeyStore文件用于数字证书的密钥对保存
- *
- * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
- * @param password 密码
- * @return {@link KeyStore}
- * @since 5.0.0
- */
- public static KeyStore readPKCS12KeyStore(final InputStream in, final char[] password) {
- return readKeyStore(KEY_TYPE_PKCS12, in, password);
- }
-
- /**
- * 读取KeyStore文件
- * KeyStore文件用于数字证书的密钥对保存
- * see: ...
- *
- * @param type 类型
- * @param keyFile 证书文件
- * @param password 密码,null表示无密码
- * @return {@link KeyStore}
- * @since 5.0.0
- */
- public static KeyStore readKeyStore(final String type, final File keyFile, final char[] password) {
- InputStream in = null;
- try {
- in = FileUtil.getInputStream(keyFile);
- return readKeyStore(type, in, password);
- } finally {
- IoUtil.closeQuietly(in);
- }
- }
-
- /**
- * 读取KeyStore文件
- * KeyStore文件用于数字证书的密钥对保存
- * see: ...
- *
- * @param type 类型
- * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(File)} 读取
- * @param password 密码,null表示无密码
- * @return {@link KeyStore}
- */
- public static KeyStore readKeyStore(final String type, final InputStream in, final char[] password) {
- final KeyStore keyStore = getKeyStore(type);
- try {
- keyStore.load(in, password);
- } catch (final Exception e) {
- throw new CryptoException(e);
- }
- return keyStore;
- }
-
- /**
- * 获取{@link KeyStore}对象
- *
- * @param type 类型
- * @return {@link KeyStore}
- */
- public static KeyStore getKeyStore(final String type) {
- final Provider provider = GlobalProviderFactory.getProvider();
- try {
- return null == provider ? KeyStore.getInstance(type) : KeyStore.getInstance(type, provider);
- } catch (final KeyStoreException e) {
- throw new CryptoException(e);
- }
- }
-
- /**
- * 从KeyStore中获取私钥公钥
- *
- * @param type 类型
- * @param in {@link InputStream} 如果想从文件读取.keystore文件,使用 {@link FileUtil#getInputStream(java.io.File)} 读取
- * @param password 密码
- * @param alias 别名
- * @return {@link KeyPair}
- * @since 4.4.1
- */
- public static KeyPair getKeyPair(final String type, final InputStream in, final char[] password, final String alias) {
- final KeyStore keyStore = readKeyStore(type, in, password);
- return getKeyPair(keyStore, password, alias);
- }
-
- /**
- * 从KeyStore中获取私钥公钥
- *
- * @param keyStore {@link KeyStore}
- * @param password 密码
- * @param alias 别名
- * @return {@link KeyPair}
- * @since 4.4.1
- */
- public static KeyPair getKeyPair(final KeyStore keyStore, final char[] password, final String alias) {
- final PublicKey publicKey;
- final PrivateKey privateKey;
- try {
- publicKey = keyStore.getCertificate(alias).getPublicKey();
- privateKey = (PrivateKey) keyStore.getKey(alias, password);
- } catch (final Exception e) {
- throw new CryptoException(e);
- }
- return new KeyPair(publicKey, privateKey);
- }
-
- /**
- * 读取X.509 Certification文件
- * Certification为证书文件
- * see: ...
- *
- * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
- * @param password 密码
- * @param alias 别名
- * @return {@link KeyStore}
- * @since 4.4.1
- */
- public static Certificate readX509Certificate(final InputStream in, final char[] password, final String alias) {
- return readCertificate(CERT_TYPE_X509, in, password, alias);
- }
-
/**
* 读取X.509 Certification文件中的公钥
* Certification为证书文件
@@ -845,98 +708,13 @@ public class KeyUtil {
* @since 4.5.2
*/
public static PublicKey readPublicKeyFromCert(final InputStream in) {
- final Certificate certificate = readX509Certificate(in);
+ final Certificate certificate = CertUtil.readX509Certificate(in);
if (null != certificate) {
return certificate.getPublicKey();
}
return null;
}
- /**
- * 读取X.509 Certification文件
- * Certification为证书文件
- * see: ...
- *
- * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
- * @return {@link KeyStore}
- * @since 4.4.1
- */
- public static Certificate readX509Certificate(final InputStream in) {
- return readCertificate(CERT_TYPE_X509, in);
- }
-
- /**
- * 读取Certification文件
- * Certification为证书文件
- * see: ...
- *
- * @param type 类型,例如X.509
- * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
- * @param password 密码
- * @param alias 别名
- * @return {@link KeyStore}
- * @since 4.4.1
- */
- public static Certificate readCertificate(final String type, final InputStream in, final char[] password, final String alias) {
- final KeyStore keyStore = readKeyStore(type, in, password);
- try {
- return keyStore.getCertificate(alias);
- } catch (final KeyStoreException e) {
- throw new CryptoException(e);
- }
- }
-
- /**
- * 读取Certification文件
- * Certification为证书文件
- * see: ...
- *
- * @param type 类型,例如X.509
- * @param in {@link InputStream} 如果想从文件读取.cer文件,使用 {@link FileUtil#getInputStream(File)} 读取
- * @return {@link Certificate}
- */
- public static Certificate readCertificate(final String type, final InputStream in) {
- try {
- return getCertificateFactory(type).generateCertificate(in);
- } catch (final CertificateException e) {
- throw new CryptoException(e);
- }
- }
-
- /**
- * 获得 Certification
- *
- * @param keyStore {@link KeyStore}
- * @param alias 别名
- * @return {@link Certificate}
- */
- public static Certificate getCertificate(final KeyStore keyStore, final String alias) {
- try {
- return keyStore.getCertificate(alias);
- } catch (final Exception e) {
- throw new CryptoException(e);
- }
- }
-
- /**
- * 获取{@link CertificateFactory}
- *
- * @param type 类型,例如X.509
- * @return {@link KeyPairGenerator}
- * @since 4.5.0
- */
- public static CertificateFactory getCertificateFactory(final String type) {
- final Provider provider = GlobalProviderFactory.getProvider();
-
- final CertificateFactory factory;
- try {
- factory = (null == provider) ? CertificateFactory.getInstance(type) : CertificateFactory.getInstance(type, provider);
- } catch (final CertificateException e) {
- throw new CryptoException(e);
- }
- return factory;
- }
-
/**
* 编码压缩EC公钥(基于BouncyCastle)
* 见:...
@@ -975,51 +753,6 @@ public class KeyUtil {
return BCUtil.decodeECPoint(encodeByte, curveName);
}
- /**
- * 通过RSA私钥生成RSA公钥
- *
- * @param privateKey RSA私钥
- * @return RSA公钥,null表示私钥不被支持
- * @since 5.3.6
- */
- public static PublicKey getRSAPublicKey(final PrivateKey privateKey) {
- if (privateKey instanceof RSAPrivateCrtKey) {
- final RSAPrivateCrtKey privk = (RSAPrivateCrtKey) privateKey;
- return getRSAPublicKey(privk.getModulus(), privk.getPublicExponent());
- }
- return null;
- }
-
- /**
- * 获得RSA公钥对象
- *
- * @param modulus Modulus
- * @param publicExponent Public Exponent
- * @return 公钥
- * @since 5.3.6
- */
- public static PublicKey getRSAPublicKey(final String modulus, final String publicExponent) {
- return getRSAPublicKey(
- new BigInteger(modulus, 16), new BigInteger(publicExponent, 16));
- }
-
- /**
- * 获得RSA公钥对象
- *
- * @param modulus Modulus
- * @param publicExponent Public Exponent
- * @return 公钥
- * @since 5.3.6
- */
- public static PublicKey getRSAPublicKey(final BigInteger modulus, final BigInteger publicExponent) {
- final RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(modulus, publicExponent);
- try {
- return getKeyFactory("RSA").generatePublic(publicKeySpec);
- } catch (final InvalidKeySpecException e) {
- throw new CryptoException(e);
- }
- }
-
/**
* 将密钥编码为Base64格式
*
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SpecUtil.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SpecUtil.java
new file mode 100644
index 000000000..f8fbf8f05
--- /dev/null
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/SpecUtil.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023 looly(loolly@aliyun.com)
+ * Hutool is licensed under Mulan PSL v2.
+ * You can use this software according to the terms and conditions of the Mulan PSL v2.
+ * You may obtain a copy of Mulan PSL v2 at:
+ * http://license.coscl.org.cn/MulanPSL2
+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
+ * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
+ * See the Mulan PSL v2 for more details.
+ */
+
+package org.dromara.hutool.crypto;
+
+import org.dromara.hutool.core.util.RandomUtil;
+
+import javax.crypto.spec.*;
+import java.security.InvalidKeyException;
+import java.security.spec.KeySpec;
+
+/**
+ * 规范相关工具类,用于生成密钥规范、参数规范等快捷方法。
+ *
+ * - {@link KeySpec}: 密钥规范
+ * - {@link java.security.spec.AlgorithmParameterSpec}: 参数规范
+ *
+ *
+ * @author looly
+ * @since 6.0.0
+ */
+public class SpecUtil {
+
+ /**
+ * 根据算法创建{@link KeySpec}
+ *
+ * - DESede: {@link DESedeKeySpec}
+ * - DES : {@link DESedeKeySpec}
+ * - 其它 : {@link SecretKeySpec}
+ *
+ *
+ * @param algorithm 算法
+ * @param key 密钥
+ * @return {@link KeySpec}
+ */
+ public static KeySpec createKeySpec(final String algorithm, byte[] key) {
+ try {
+ if (algorithm.startsWith("DESede")) {
+ if (null == key) {
+ key = RandomUtil.randomBytes(24);
+ }
+ // DESede兼容
+ return new DESedeKeySpec(key);
+ } else if (algorithm.startsWith("DES")) {
+ if (null == key) {
+ key = RandomUtil.randomBytes(8);
+ }
+ return new DESKeySpec(key);
+ }
+ } catch (final InvalidKeyException e) {
+ throw new CryptoException(e);
+ }
+
+ return new SecretKeySpec(key, algorithm);
+ }
+
+ /**
+ * 创建{@link PBEKeySpec}
+ * PBE算法没有密钥的概念,密钥在其它对称加密算法中是经过算法计算得出来的,PBE算法则是使用口令替代了密钥。
+ *
+ * @param password 口令
+ * @return {@link PBEKeySpec}
+ */
+ public static PBEKeySpec createPBEKeySpec(char[] password) {
+ if (null == password) {
+ password = RandomUtil.randomString(32).toCharArray();
+ }
+ return new PBEKeySpec(password);
+ }
+
+ /**
+ * 创建{@link PBEParameterSpec}
+ *
+ * @param salt 加盐值
+ * @param iterationCount 摘要次数
+ * @return {@link PBEParameterSpec}
+ */
+ public static PBEParameterSpec createPBEParameterSpec(final byte[] salt, final int iterationCount) {
+ return new PBEParameterSpec(salt, iterationCount);
+ }
+}
diff --git a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/openssl/OpenSSLPBECommon.java b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/openssl/OpenSSLPBECommon.java
index 204968f48..aab8966c5 100755
--- a/hutool-crypto/src/main/java/org/dromara/hutool/crypto/openssl/OpenSSLPBECommon.java
+++ b/hutool-crypto/src/main/java/org/dromara/hutool/crypto/openssl/OpenSSLPBECommon.java
@@ -33,9 +33,9 @@ public class OpenSSLPBECommon {
final String algorithm, int iterationCount)
throws Exception {
- final SecretKey key = KeyUtil.generateKey(algorithm, new PBEKeySpec(password));
-
final Cipher cipher = SecureUtil.createCipher(algorithm);
+
+ final SecretKey key = KeyUtil.generateKey(algorithm, new PBEKeySpec(password));
cipher.init(cipherMode, key, new PBEParameterSpec(salt, iterationCount));
return cipher;
diff --git a/hutool-crypto/src/test/java/org/dromara/hutool/crypto/asymmetric/SM2Test.java b/hutool-crypto/src/test/java/org/dromara/hutool/crypto/asymmetric/SM2Test.java
index 0da49c15f..b0e46d84b 100644
--- a/hutool-crypto/src/test/java/org/dromara/hutool/crypto/asymmetric/SM2Test.java
+++ b/hutool-crypto/src/test/java/org/dromara/hutool/crypto/asymmetric/SM2Test.java
@@ -190,8 +190,8 @@ public class SM2Test {
final byte[] data = KeyUtil.encodeECPublicKey(publicKey);
final String encodeHex = HexUtil.encodeHexStr(data);
final String encodeB64 = Base64.encode(data);
- final PublicKey Hexdecode = KeyUtil.decodeECPoint(encodeHex, KeyUtil.SM2_DEFAULT_CURVE);
- final PublicKey B64decode = KeyUtil.decodeECPoint(encodeB64, KeyUtil.SM2_DEFAULT_CURVE);
+ final PublicKey Hexdecode = KeyUtil.decodeECPoint(encodeHex, SmUtil.SM2_CURVE_NAME);
+ final PublicKey B64decode = KeyUtil.decodeECPoint(encodeB64, SmUtil.SM2_CURVE_NAME);
Assertions.assertEquals(HexUtil.encodeHexStr(publicKey.getEncoded()), HexUtil.encodeHexStr(Hexdecode.getEncoded()));
Assertions.assertEquals(HexUtil.encodeHexStr(publicKey.getEncoded()), HexUtil.encodeHexStr(B64decode.getEncoded()));
}