diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc6026215..6d5ab5f90 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -21,6 +21,7 @@
* 【core 】 增加TemporalAccessorUtil.isIn、LocalDateTimeUtil.isIn(issue#I5HBL0@Gitee)
* 【core 】 ReUtil增加getAllGroups重载(pr#2455@Github)
* 【core 】 PageUtil#totalPage增加totalCount为long类型的重载方法(pr#2442@Github)
+* 【crypto 】 PemUtil.readPemPrivateKey支持pkcs#1格式,增加OpensslKeyUtil(pr#2456@Github)
*
### 🐞Bug修复
* 【core 】 修复CollUtil里面关于可变参数传null造成的crash问题(pr#2428@Github)
diff --git a/hutool-crypto/pom.xml b/hutool-crypto/pom.xml
index 30d01cf06..6e7b7ea26 100755
--- a/hutool-crypto/pom.xml
+++ b/hutool-crypto/pom.xml
@@ -18,7 +18,7 @@
- 1.70
+ 1.71
@@ -29,14 +29,7 @@
org.bouncycastle
- bcprov-jdk15to18
- ${bouncycastle.version}
- compile
- true
-
-
- org.bouncycastle
- bcpkix-jdk15on
+ bcpkix-jdk15to18
${bouncycastle.version}
compile
true
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/OpensslKeyUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/OpensslKeyUtil.java
new file mode 100644
index 000000000..6748a79ea
--- /dev/null
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/OpensslKeyUtil.java
@@ -0,0 +1,187 @@
+package cn.hutool.crypto;
+
+import cn.hutool.core.io.IORuntimeException;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
+import org.bouncycastle.openssl.PEMException;
+import org.bouncycastle.openssl.PEMKeyPair;
+import org.bouncycastle.openssl.PEMParser;
+import org.bouncycastle.openssl.X509TrustedCertificateBlock;
+import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
+import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
+import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
+import org.bouncycastle.operator.InputDecryptorProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
+import org.bouncycastle.pkcs.PKCSException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+/**
+ * 基于bcpkix封装的Openssl相关工具,包括密钥转换、Pem密钥文件读取等
+ * 注意此工具需要引入org.bouncycastle:bcpkix-jdk15to18
+ *
+ * @author changhr2013, looly
+ * @since 5.8.5
+ */
+public class OpensslKeyUtil {
+
+ private static final JcaPEMKeyConverter pemKeyConverter = new JcaPEMKeyConverter().setProvider(GlobalBouncyCastleProvider.INSTANCE.getProvider());
+
+ /**
+ * 转换{@link PrivateKeyInfo}为{@link PrivateKey}
+ *
+ * @param privateKeyInfo {@link PrivateKeyInfo}
+ * @return {@link PrivateKey}
+ * @throws CryptoException {@link PEMException}包装
+ */
+ public static PrivateKey getPrivateKey(final PrivateKeyInfo privateKeyInfo) throws CryptoException {
+ try {
+ return pemKeyConverter.getPrivateKey(privateKeyInfo);
+ } catch (final PEMException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 转换{@link SubjectPublicKeyInfo}为{@link PublicKey}
+ *
+ * @param publicKeyInfo {@link SubjectPublicKeyInfo}
+ * @return {@link PublicKey}
+ * @throws CryptoException {@link PEMException}包装
+ */
+ public static PublicKey getPublicKey(final SubjectPublicKeyInfo publicKeyInfo) throws CryptoException {
+ try {
+ return pemKeyConverter.getPublicKey(publicKeyInfo);
+ } catch (final PEMException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 转换{@link PEMKeyPair}为{@link KeyPair}
+ *
+ * @param keyPair {@link PEMKeyPair}
+ * @return {@link KeyPair}
+ * @throws CryptoException {@link PEMException}包装
+ */
+ public static KeyPair getKeyPair(final PEMKeyPair keyPair) throws CryptoException {
+ try {
+ return pemKeyConverter.getKeyPair(keyPair);
+ } catch (final PEMException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 从pem文件中读取公钥或私钥
+ * 根据类型返回 {@link PublicKey} 或者 {@link PrivateKey}
+ *
+ * @param keyStream pem 流
+ * @param password 私钥密码
+ * @return {@link Key},null 表示无法识别的密钥类型
+ * @since 5.8.5
+ */
+ public static Key readPemKey(final InputStream keyStream, final char[] password) {
+ try (final PEMParser pemParser = new PEMParser(new InputStreamReader(keyStream))) {
+ return readPemKeyFromKeyObject(pemParser.readObject(), password);
+ } catch (final IOException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 解密{@link PKCS8EncryptedPrivateKeyInfo}为{@link PrivateKeyInfo}
+ *
+ * @param pkcs8Info {@link PKCS8EncryptedPrivateKeyInfo}
+ * @param password 密码
+ * @return {@link PrivateKeyInfo}
+ * @throws CryptoException OperatorCreationException和PKCSException包装
+ */
+ public static PrivateKeyInfo decrypt(final PKCS8EncryptedPrivateKeyInfo pkcs8Info, final char[] password) throws CryptoException {
+ final InputDecryptorProvider decryptProvider;
+ try {
+ decryptProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider(GlobalBouncyCastleProvider.INSTANCE.getProvider()).build(password);
+ return pkcs8Info.decryptPrivateKeyInfo(decryptProvider);
+ } catch (final OperatorCreationException | PKCSException e) {
+ throw new CryptoException(e);
+ }
+ }
+
+ /**
+ * 解密{@link PEMEncryptedKeyPair}为{@link PEMKeyPair}
+ *
+ * @param pemEncryptedKeyPair {@link PKCS8EncryptedPrivateKeyInfo}
+ * @param password 密码
+ * @return {@link PEMKeyPair}
+ * @throws IORuntimeException IOException包装
+ */
+ public static PEMKeyPair decrypt(final PEMEncryptedKeyPair pemEncryptedKeyPair, final char[] password) throws IORuntimeException {
+ final PEMDecryptorProvider decryptProvider;
+ try {
+ decryptProvider = new JcePEMDecryptorProviderBuilder().setProvider(GlobalBouncyCastleProvider.INSTANCE.getProvider()).build(password);
+ return pemEncryptedKeyPair.decryptKeyPair(decryptProvider);
+ } catch (final IOException e) {
+ throw new IORuntimeException(e);
+ }
+ }
+
+ /**
+ * 读取Pem文件中的密钥,密钥支持包括:
+ *
+ * - {@link PrivateKeyInfo}
+ * - {@link PEMKeyPair},默认读取私钥
+ * - {@link PKCS8EncryptedPrivateKeyInfo}
+ * - {@link PEMEncryptedKeyPair},默认读取私钥
+ * - {@link X509CertificateHolder}
+ * - {@link X509TrustedCertificateBlock}
+ * - {@link PKCS10CertificationRequest}
+ *
+ *
+ * @param keyObject 密钥内容对象
+ * @param password 密码(部分加密的pem使用)
+ * @return {@link Key}
+ * @throws CryptoException 读取异常或不支持的类型
+ */
+ private static Key readPemKeyFromKeyObject(final Object keyObject, final char[] password) throws CryptoException {
+ if (keyObject instanceof PrivateKeyInfo) {
+ // PrivateKeyInfo
+ return getPrivateKey((PrivateKeyInfo) keyObject);
+ } else if (keyObject instanceof PEMKeyPair) {
+ // PemKeyPair
+ return getKeyPair((PEMKeyPair) keyObject).getPrivate();
+ } else if (keyObject instanceof PKCS8EncryptedPrivateKeyInfo) {
+ // Encrypted PrivateKeyInfo
+ return getPrivateKey(decrypt((PKCS8EncryptedPrivateKeyInfo) keyObject, password));
+ } else if (keyObject instanceof PEMEncryptedKeyPair) {
+ // Encrypted PemKeyPair
+ return getPrivateKey(decrypt((PEMEncryptedKeyPair) keyObject, password).getPrivateKeyInfo());
+ } else if (keyObject instanceof SubjectPublicKeyInfo) {
+ // SubjectPublicKeyInfo
+ return getPublicKey((SubjectPublicKeyInfo) keyObject);
+ } else if (keyObject instanceof X509CertificateHolder) {
+ // X509 Certificate
+ return getPublicKey(((X509CertificateHolder) keyObject).getSubjectPublicKeyInfo());
+ } else if (keyObject instanceof X509TrustedCertificateBlock) {
+ // X509 Trusted Certificate
+ return getPublicKey(((X509TrustedCertificateBlock) keyObject).getCertificateHolder().getSubjectPublicKeyInfo());
+ } else if (keyObject instanceof PKCS10CertificationRequest) {
+ // PKCS#10 CSR
+ return getPublicKey(((PKCS10CertificationRequest) keyObject).getSubjectPublicKeyInfo());
+ } else {
+ // 表示无法识别的密钥类型
+ throw new CryptoException("Unsupported key object type: {}", keyObject.getClass());
+ }
+ }
+}
diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java
index 180cf4186..d9b5edfaa 100644
--- a/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java
+++ b/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java
@@ -2,27 +2,21 @@ package cn.hutool.crypto;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.io.IoUtil;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.openssl.*;
-import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
-import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
-import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
-import org.bouncycastle.operator.InputDecryptorProvider;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.pkcs.PKCS10CertificationRequest;
-import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
-import org.bouncycastle.pkcs.PKCSException;
+import cn.hutool.core.util.StrUtil;
+
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemObjectGenerator;
import org.bouncycastle.util.io.pem.PemReader;
import org.bouncycastle.util.io.pem.PemWriter;
-import java.io.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
import java.security.Key;
import java.security.PrivateKey;
-import java.security.Provider;
import java.security.PublicKey;
/**
@@ -39,7 +33,7 @@ import java.security.PublicKey;
public class PemUtil {
/**
- * 读取PEM格式的私钥
+ * 读取PEM格式的私钥,支持PKCS#8和PKCS#1的ECC格式
*
* @param pemStream pem流
* @return {@link PrivateKey}
@@ -49,18 +43,6 @@ public class PemUtil {
return (PrivateKey) readPemKey(pemStream);
}
- /**
- * 读取加密的 PEM 格式私钥
- *
- * @param pemStream pem 流
- * @param password 私钥的密码
- * @return {@link PrivateKey}
- * @since 5.8.4
- */
- public static PrivateKey readPemPrivateKey(InputStream pemStream, final char[] password) {
- return (PrivateKey) readPemKey(pemStream, password);
- }
-
/**
* 读取PEM格式的公钥
*
@@ -81,63 +63,41 @@ public class PemUtil {
* @since 5.1.6
*/
public static Key readPemKey(InputStream keyStream) {
- return readPemKey(keyStream, null);
- }
-
- /**
- * 从pem文件中读取公钥或私钥
- * 根据类型返回 {@link PublicKey} 或者 {@link PrivateKey}
- *
- * @param keyStream pem 流
- * @param password 私钥密码
- * @return {@link Key},null 表示无法识别的密钥类型
- * @since 5.8.4
- */
- public static Key readPemKey(InputStream keyStream, final char[] password) {
-
- final Provider provider = GlobalBouncyCastleProvider.INSTANCE.getProvider();
-
- try (PEMParser pemParser = new PEMParser(new InputStreamReader(keyStream))) {
-
- Object keyObject = pemParser.readObject();
-
- JcaPEMKeyConverter pemKeyConverter = new JcaPEMKeyConverter().setProvider(provider);
-
- if (keyObject instanceof PrivateKeyInfo) {
- // PrivateKeyInfo
- return pemKeyConverter.getPrivateKey((PrivateKeyInfo) keyObject);
- } else if (keyObject instanceof PEMKeyPair) {
- // PemKeyPair
- return pemKeyConverter.getKeyPair((PEMKeyPair) keyObject).getPrivate();
- } else if (keyObject instanceof PKCS8EncryptedPrivateKeyInfo) {
- // Encrypted PrivateKeyInfo
- InputDecryptorProvider decryptProvider = new JceOpenSSLPKCS8DecryptorProviderBuilder().setProvider(provider).build(password);
- PrivateKeyInfo privateKeyInfo = ((PKCS8EncryptedPrivateKeyInfo) keyObject).decryptPrivateKeyInfo(decryptProvider);
- return pemKeyConverter.getPrivateKey(privateKeyInfo);
- } else if (keyObject instanceof PEMEncryptedKeyPair) {
- // Encrypted PemKeyPair
- PEMDecryptorProvider decryptProvider = new JcePEMDecryptorProviderBuilder().setProvider(provider).build(password);
- PrivateKeyInfo privateKeyInfo = ((PEMEncryptedKeyPair) keyObject).decryptKeyPair(decryptProvider).getPrivateKeyInfo();
- return pemKeyConverter.getPrivateKey(privateKeyInfo);
- } else if (keyObject instanceof SubjectPublicKeyInfo) {
- // SubjectPublicKeyInfo
- return pemKeyConverter.getPublicKey((SubjectPublicKeyInfo) keyObject);
- } else if (keyObject instanceof X509CertificateHolder) {
- // X509 Certificate
- return pemKeyConverter.getPublicKey(((X509CertificateHolder) keyObject).getSubjectPublicKeyInfo());
- } else if (keyObject instanceof X509TrustedCertificateBlock) {
- // X509 Trusted Certificate
- return pemKeyConverter.getPublicKey(((X509TrustedCertificateBlock) keyObject).getCertificateHolder().getSubjectPublicKeyInfo());
- } else if (keyObject instanceof PKCS10CertificationRequest) {
- // PKCS#10 CSR
- return pemKeyConverter.getPublicKey(((PKCS10CertificationRequest) keyObject).getSubjectPublicKeyInfo());
- } else {
- // 表示无法识别的密钥类型
- return null;
+ final PemObject object = readPemObject(keyStream);
+ final String type = object.getType();
+ if (StrUtil.isNotBlank(type)) {
+ //private
+ if (type.endsWith("EC PRIVATE KEY")) {
+ try {
+ // 尝试PKCS#8
+ return KeyUtil.generatePrivateKey("EC", object.getContent());
+ } catch (final Exception e) {
+ // 尝试PKCS#1
+ return KeyUtil.generatePrivateKey("EC", ECKeyUtil.createOpenSSHPrivateKeySpec(object.getContent()));
+ }
+ }
+ if (type.endsWith("PRIVATE KEY")) {
+ return KeyUtil.generateRSAPrivateKey(object.getContent());
+ }
+
+ // public
+ if (type.endsWith("EC PUBLIC KEY")) {
+ try {
+ // 尝试DER
+ return KeyUtil.generatePublicKey("EC", object.getContent());
+ } catch (Exception e) {
+ // 尝试PKCS#1
+ return KeyUtil.generatePublicKey("EC", ECKeyUtil.createOpenSSHPublicKeySpec(object.getContent()));
+ }
+ } else if (type.endsWith("PUBLIC KEY")) {
+ return KeyUtil.generateRSAPublicKey(object.getContent());
+ } else if (type.endsWith("CERTIFICATE")) {
+ return KeyUtil.readPublicKeyFromCert(IoUtil.toStream(object.getContent()));
}
- } catch (IOException | OperatorCreationException | PKCSException e) {
- throw new RuntimeException(e);
}
+
+ //表示无法识别的密钥类型
+ return null;
}
/**
@@ -148,7 +108,7 @@ public class PemUtil {
* @since 5.1.6
*/
public static byte[] readPem(InputStream keyStream) {
- PemObject pemObject = readPemObject(keyStream);
+ final PemObject pemObject = readPemObject(keyStream);
if (null != pemObject) {
return pemObject.getContent();
}
@@ -190,7 +150,9 @@ public class PemUtil {
*
* @param keyStream 私钥pem流
* @return {@link PrivateKey}
+ * @deprecated 请使用 {@link #readPemPrivateKey(InputStream)}
*/
+ @Deprecated
public static PrivateKey readSm2PemPrivateKey(InputStream keyStream) {
return readPemPrivateKey(keyStream);
}
@@ -225,7 +187,7 @@ public class PemUtil {
* 写出pem密钥(私钥、公钥、证书)
*
* @param type 密钥类型(私钥、公钥、证书)
- * @param content 密钥内容,需为PKCS#1格式
+ * @param content 密钥内容,需为PKCS#1或PKCS#8格式
* @param writer pemWriter
* @since 5.5.9
*/
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/BCUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java
similarity index 96%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/BCUtilTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java
index 8a922cdef..68971d361 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/BCUtilTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/BCUtilTest.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test;
+package cn.hutool.crypto;
import cn.hutool.crypto.BCUtil;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/KeyUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java
similarity index 98%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/KeyUtilTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java
index 576a85cf8..2ef57eea2 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/KeyUtilTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/KeyUtilTest.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test;
+package cn.hutool.crypto;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.GlobalBouncyCastleProvider;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/OpensslKeyUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/OpensslKeyUtilTest.java
new file mode 100644
index 000000000..a6348ce6b
--- /dev/null
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/OpensslKeyUtilTest.java
@@ -0,0 +1,55 @@
+package cn.hutool.crypto;
+
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.asymmetric.SM2;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Arrays;
+import java.util.List;
+
+public class OpensslKeyUtilTest {
+ @Test
+ public void verifyPemUtilReadKey() {
+ // 公钥
+ // PKCS#10 文件读取公钥
+ final PublicKey csrPublicKey = (PublicKey) OpensslKeyUtil.readPemKey(ResourceUtil.getStream("test_ec_certificate_request.csr"), null);
+
+ // 证书读取公钥
+ final PublicKey certPublicKey = (PublicKey) OpensslKeyUtil.readPemKey(ResourceUtil.getStream("test_ec_certificate.cer"), null);
+
+ // PEM 公钥
+ final PublicKey plainPublicKey = (PublicKey) OpensslKeyUtil.readPemKey(ResourceUtil.getStream("test_ec_public_key.pem"), null);
+
+ // 私钥
+ // 加密的 PEM 私钥
+ final PrivateKey encPrivateKey = (PrivateKey) OpensslKeyUtil.readPemKey(ResourceUtil.getStream("test_ec_encrypted_private_key.key"), "123456".toCharArray());
+
+ // PKCS#8 私钥
+ final PrivateKey pkcs8PrivateKey = (PrivateKey) OpensslKeyUtil.readPemKey(ResourceUtil.getStream("test_ec_pkcs8_private_key.key"), null);
+
+ // SEC 1 私钥
+ final PrivateKey sec1PrivateKey = (PrivateKey) OpensslKeyUtil.readPemKey(ResourceUtil.getStream("test_ec_sec1_private_key.pem"), null);
+
+ // 组装还原后的公钥和私钥列表
+ final List publicKeyList = Arrays.asList(csrPublicKey, certPublicKey, plainPublicKey);
+ final List privateKeyList = Arrays.asList(encPrivateKey, pkcs8PrivateKey, sec1PrivateKey);
+
+ // 做笛卡尔积循环验证
+ for (final PrivateKey privateKeyItem : privateKeyList) {
+ for (final PublicKey publicKeyItem : publicKeyList) {
+ // 校验公私钥
+ final SM2 genSm2 = new SM2(privateKeyItem, publicKeyItem);
+ genSm2.usePlainEncoding();
+
+ final String content = "我是Hanley.";
+ final byte[] sign = genSm2.sign(StrUtil.utf8Bytes(content));
+ final boolean verify = genSm2.verify(StrUtil.utf8Bytes(content), sign);
+ Assert.assertTrue(verify);
+ }
+ }
+ }
+}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/PemUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/PemUtilTest.java
new file mode 100644
index 000000000..3585c20ea
--- /dev/null
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/PemUtilTest.java
@@ -0,0 +1,80 @@
+package cn.hutool.crypto;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.resource.ResourceUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import cn.hutool.crypto.asymmetric.SM2;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.nio.charset.StandardCharsets;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+public class PemUtilTest {
+
+ @Test
+ public void readPrivateKeyTest() {
+ final PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
+ Assert.assertNotNull(privateKey);
+ }
+
+ @Test
+ public void readPublicKeyTest() {
+ final PublicKey publicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_public_key.csr"));
+ Assert.assertNotNull(publicKey);
+ }
+
+ @Test
+ public void readPemKeyTest() {
+ final PublicKey publicKey = (PublicKey) PemUtil.readPemKey(ResourceUtil.getStream("test_public_key.csr"));
+ Assert.assertNotNull(publicKey);
+ }
+
+ @Test
+ public void validateKey() {
+ final PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
+ final PublicKey publicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_public_key.csr"));
+
+ final RSA rsa = new RSA(privateKey, publicKey);
+ final String str = "你好,Hutool";//测试字符串
+
+ final String encryptStr = rsa.encryptBase64(str, KeyType.PublicKey);
+ final String decryptStr = rsa.decryptStr(encryptStr, KeyType.PrivateKey);
+ Assert.assertEquals(str, decryptStr);
+ }
+
+ @Test
+ public void readECPrivateKeyTest() {
+ final PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_ec_sec1_private_key.pem"));
+ final SM2 sm2 = new SM2(privateKey, null);
+ sm2.usePlainEncoding();
+
+ //需要签名的明文,得到明文对应的字节数组
+ final byte[] dataBytes = "我是一段测试aaaa".getBytes(StandardCharsets.UTF_8);
+
+ final byte[] sign = sm2.sign(dataBytes, null);
+ // 64位签名
+ Assert.assertEquals(64, sign.length);
+ }
+
+ @Test
+ @Ignore
+ public void readECPrivateKeyTest2() {
+ // https://gitee.com/dromara/hutool/issues/I37Z75
+ final byte[] d = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/priv.key"));
+ final byte[] publicKey = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/pub.key"));
+
+ final SM2 sm2 = new SM2(d, publicKey);
+ sm2.usePlainEncoding();
+
+ final String content = "我是Hanley.";
+ final byte[] sign = sm2.sign(StrUtil.utf8Bytes(content));
+ final boolean verify = sm2.verify(StrUtil.utf8Bytes(content), sign);
+ Assert.assertTrue(verify);
+ }
+
+}
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/SmTest.java
similarity index 98%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/SmTest.java
index 5888cdf08..fa6ea25b2 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/SmTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/SmTest.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test;
+package cn.hutool.crypto;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.KeyUtil;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/ECIESTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/ECIESTest.java
similarity index 85%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/ECIESTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/ECIESTest.java
index 6e91f8a89..3ac2b222a 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/ECIESTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/ECIESTest.java
@@ -1,9 +1,6 @@
-package cn.hutool.crypto.test.asymmetric;
+package cn.hutool.crypto.asymmetric;
import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.asymmetric.AsymmetricCrypto;
-import cn.hutool.crypto.asymmetric.ECIES;
-import cn.hutool.crypto.asymmetric.KeyType;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/RSATest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/RSATest.java
old mode 100755
new mode 100644
similarity index 96%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/RSATest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/RSATest.java
index a8351c341..6f962c6c5
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/RSATest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/RSATest.java
@@ -1,7 +1,6 @@
-package cn.hutool.crypto.test.asymmetric;
+package cn.hutool.crypto.asymmetric;
import cn.hutool.core.codec.Base64;
-import cn.hutool.core.lang.Console;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HexUtil;
@@ -9,11 +8,6 @@ import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-import cn.hutool.crypto.asymmetric.Sign;
-import cn.hutool.crypto.asymmetric.SignAlgorithm;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/SM2Test.java
old mode 100755
new mode 100644
similarity index 98%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/SM2Test.java
index 3e852793d..60eea17d5
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SM2Test.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/SM2Test.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test.asymmetric;
+package cn.hutool.crypto.asymmetric;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
@@ -8,8 +8,6 @@ import cn.hutool.crypto.ECKeyUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/SignTest.java
similarity index 97%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/SignTest.java
index 0bc8f268f..003d69604 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/asymmetric/SignTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/asymmetric/SignTest.java
@@ -1,10 +1,8 @@
-package cn.hutool.crypto.test.asymmetric;
+package cn.hutool.crypto.asymmetric;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.asymmetric.Sign;
-import cn.hutool.crypto.asymmetric.SignAlgorithm;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/BCryptTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/BCryptTest.java
similarity index 75%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/BCryptTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/digest/BCryptTest.java
index 3450355ab..7ab03177b 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/BCryptTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/BCryptTest.java
@@ -1,6 +1,5 @@
-package cn.hutool.crypto.test.digest;
+package cn.hutool.crypto.digest;
-import cn.hutool.crypto.digest.BCrypt;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/CBCBlockCipherMacEngineTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/CBCBlockCipherMacEngineTest.java
similarity index 97%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/CBCBlockCipherMacEngineTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/digest/CBCBlockCipherMacEngineTest.java
index 8e4bdb6e3..85fbbbd55 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/CBCBlockCipherMacEngineTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/CBCBlockCipherMacEngineTest.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test.digest;
+package cn.hutool.crypto.digest;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.digest.mac.Mac;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/DigestTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/DigestTest.java
similarity index 90%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/DigestTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/digest/DigestTest.java
index d555b4ec4..80acd8c4f 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/DigestTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/DigestTest.java
@@ -1,12 +1,9 @@
-package cn.hutool.crypto.test.digest;
+package cn.hutool.crypto.digest;
import org.junit.Assert;
import org.junit.Test;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.crypto.digest.DigestAlgorithm;
-import cn.hutool.crypto.digest.DigestUtil;
-import cn.hutool.crypto.digest.Digester;
/**
* 摘要算法单元测试
@@ -14,40 +11,40 @@ import cn.hutool.crypto.digest.Digester;
*
*/
public class DigestTest {
-
+
@Test
public void digesterTest(){
String testStr = "test中文";
-
+
Digester md5 = new Digester(DigestAlgorithm.MD5);
String digestHex = md5.digestHex(testStr);
Assert.assertEquals("5393554e94bf0eb6436f240a4fd71282", digestHex);
}
-
+
@Test
public void md5Test(){
String testStr = "test中文";
-
+
String md5Hex1 = DigestUtil.md5Hex(testStr);
Assert.assertEquals("5393554e94bf0eb6436f240a4fd71282", md5Hex1);
-
+
String md5Hex2 = DigestUtil.md5Hex(IoUtil.toStream(testStr, CharsetUtil.CHARSET_UTF_8));
Assert.assertEquals("5393554e94bf0eb6436f240a4fd71282", md5Hex2);
}
-
+
@Test
public void md5WithSaltTest(){
String testStr = "test中文";
-
+
Digester md5 = new Digester(DigestAlgorithm.MD5);
-
+
//加盐
md5.setSalt("saltTest".getBytes());
String md5Hex1 = md5.digestHex(testStr);
Assert.assertEquals("762f7335200299dfa09bebbb601a5bc6", md5Hex1);
String md5Hex2 = md5.digestHex(IoUtil.toUtf8Stream(testStr));
Assert.assertEquals("762f7335200299dfa09bebbb601a5bc6", md5Hex2);
-
+
//重复2次
md5.setDigestCount(2);
String md5Hex3 = md5.digestHex(testStr);
@@ -55,18 +52,18 @@ public class DigestTest {
String md5Hex4 = md5.digestHex(IoUtil.toUtf8Stream(testStr));
Assert.assertEquals("2b0616296f6755d25efc07f90afe9684", md5Hex4);
}
-
+
@Test
public void sha1Test(){
String testStr = "test中文";
-
+
String sha1Hex1 = DigestUtil.sha1Hex(testStr);
Assert.assertEquals("ecabf586cef0d3b11c56549433ad50b81110a836", sha1Hex1);
-
+
String sha1Hex2 = DigestUtil.sha1Hex(IoUtil.toStream(testStr, CharsetUtil.CHARSET_UTF_8));
Assert.assertEquals("ecabf586cef0d3b11c56549433ad50b81110a836", sha1Hex2);
}
-
+
@Test
public void hash256Test() {
String testStr = "Test中文";
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/HmacTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/HmacTest.java
similarity index 95%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/HmacTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/digest/HmacTest.java
index ccddaa43c..d7fb4d939 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/HmacTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/HmacTest.java
@@ -1,11 +1,9 @@
-package cn.hutool.crypto.test.digest;
+package cn.hutool.crypto.digest;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.digest.HMac;
-import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.crypto.symmetric.ZUC;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/Md5Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/Md5Test.java
similarity index 79%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/Md5Test.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/digest/Md5Test.java
index 49cba7751..2c7cdb407 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/Md5Test.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/Md5Test.java
@@ -1,13 +1,11 @@
-package cn.hutool.crypto.test.digest;
+package cn.hutool.crypto.digest;
import org.junit.Assert;
import org.junit.Test;
-import cn.hutool.crypto.digest.MD5;
-
/**
* MD5 单元测试
- *
+ *
* @author Looly
*
*/
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/OTPTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/OTPTest.java
similarity index 98%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/OTPTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/digest/OTPTest.java
index b073d9c4b..c63aea4c7 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/digest/OTPTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/digest/OTPTest.java
@@ -1,7 +1,6 @@
-package cn.hutool.crypto.test.digest;
+package cn.hutool.crypto.digest;
import cn.hutool.core.codec.Base32;
-import cn.hutool.crypto.digest.HmacAlgorithm;
import cn.hutool.crypto.digest.otp.HOTP;
import cn.hutool.crypto.digest.otp.TOTP;
import org.junit.Assert;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/AESTest.java
old mode 100755
new mode 100644
similarity index 98%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/AESTest.java
index b860854f2..3dd30e4b2
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/AESTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/AESTest.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.HexUtil;
@@ -6,7 +6,6 @@ import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
-import cn.hutool.crypto.symmetric.AES;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ChaCha20Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/ChaCha20Test.java
similarity index 90%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ChaCha20Test.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/ChaCha20Test.java
index a30e28f0b..888720ca1 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ChaCha20Test.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/ChaCha20Test.java
@@ -1,8 +1,7 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
-import cn.hutool.crypto.symmetric.ChaCha20;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/DesTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/DesTest.java
similarity index 92%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/DesTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/DesTest.java
index eb0130c4f..acd584cea 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/DesTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/DesTest.java
@@ -1,10 +1,9 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.symmetric.DES;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/PBKDF2Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/PBKDF2Test.java
similarity index 88%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/PBKDF2Test.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/PBKDF2Test.java
index 780781ee2..7e6c2138a 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/PBKDF2Test.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/PBKDF2Test.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/RC4Test.java
similarity index 96%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/RC4Test.java
index d630af7f2..7d4cec54c 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/RC4Test.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/RC4Test.java
@@ -1,13 +1,11 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.util.CharsetUtil;
import org.junit.Assert;
import org.junit.Test;
-import cn.hutool.crypto.symmetric.RC4;
-
public class RC4Test {
-
+
@Test
public void testCryptMessage() {
String key = "This is pretty long key";
@@ -16,7 +14,7 @@ public class RC4Test {
byte[] crypt = rc4.encrypt(message);
String msg = rc4.decrypt(crypt);
Assert.assertEquals(message, msg);
-
+
String message2 = "Hello, World, this is megssage 2";
byte[] crypt2 = rc4.encrypt(message2);
String msg2 = rc4.decrypt(crypt2);
@@ -31,7 +29,7 @@ public class RC4Test {
byte[] crypt = rc4.encrypt(message);
String msg = rc4.decrypt(crypt);
Assert.assertEquals(message, msg);
-
+
String message2 = "这是第二个中文消息!";
byte[] crypt2 = rc4.encrypt(message2);
String msg2 = rc4.decrypt(crypt2);
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/Sm4StreamTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/Sm4StreamTest.java
similarity index 93%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/Sm4StreamTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/Sm4StreamTest.java
index 87ec2675c..e31a93841 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/Sm4StreamTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/Sm4StreamTest.java
@@ -1,6 +1,5 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
-import cn.hutool.crypto.symmetric.SM4;
import org.junit.Ignore;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/SymmetricTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/SymmetricTest.java
similarity index 96%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/SymmetricTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/SymmetricTest.java
index a1f4e04e6..eeee72a2f 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/SymmetricTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/SymmetricTest.java
@@ -1,4 +1,4 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
@@ -9,12 +9,6 @@ import cn.hutool.crypto.KeyUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.SecureUtil;
-import cn.hutool.crypto.symmetric.AES;
-import cn.hutool.crypto.symmetric.DES;
-import cn.hutool.crypto.symmetric.DESede;
-import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
-import cn.hutool.crypto.symmetric.SymmetricCrypto;
-import cn.hutool.crypto.symmetric.Vigenere;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/TEATest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/TEATest.java
similarity index 89%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/TEATest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/TEATest.java
index 53916926a..7044db722 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/TEATest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/TEATest.java
@@ -1,7 +1,5 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
-import cn.hutool.crypto.symmetric.SymmetricCrypto;
-import cn.hutool.crypto.symmetric.XXTEA;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ZucTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/ZucTest.java
similarity index 92%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ZucTest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/ZucTest.java
index 81524d95c..1c384ffff 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/ZucTest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/ZucTest.java
@@ -1,8 +1,7 @@
-package cn.hutool.crypto.test.symmetric;
+package cn.hutool.crypto.symmetric;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
-import cn.hutool.crypto.symmetric.ZUC;
import org.junit.Assert;
import org.junit.Test;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/fpe/FPETest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/fpe/FPETest.java
similarity index 94%
rename from hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/fpe/FPETest.java
rename to hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/fpe/FPETest.java
index dd41cbf69..25c667886 100644
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/symmetric/fpe/FPETest.java
+++ b/hutool-crypto/src/test/java/cn/hutool/crypto/symmetric/fpe/FPETest.java
@@ -1,7 +1,6 @@
-package cn.hutool.crypto.test.symmetric.fpe;
+package cn.hutool.crypto.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;
diff --git a/hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java b/hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java
deleted file mode 100644
index f6541d5bd..000000000
--- a/hutool-crypto/src/test/java/cn/hutool/crypto/test/PemUtilTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package cn.hutool.crypto.test;
-
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.resource.ResourceUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.crypto.PemUtil;
-import cn.hutool.crypto.asymmetric.KeyType;
-import cn.hutool.crypto.asymmetric.RSA;
-import cn.hutool.crypto.asymmetric.SM2;
-import org.junit.Assert;
-import org.junit.Ignore;
-import org.junit.Test;
-
-import java.nio.charset.StandardCharsets;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.util.*;
-
-public class PemUtilTest {
-
- @Test
- public void readPrivateKeyTest() {
- PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
- Assert.assertNotNull(privateKey);
- }
-
- @Test
- public void readPublicKeyTest() {
- PublicKey publicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_public_key.csr"));
- Assert.assertNotNull(publicKey);
- }
-
- @Test
- public void readPemKeyTest() {
- PublicKey publicKey = (PublicKey) PemUtil.readPemKey(ResourceUtil.getStream("test_public_key.csr"));
- Assert.assertNotNull(publicKey);
- }
-
- @Test
- public void validateKey() {
- PrivateKey privateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_private_key.pem"));
- PublicKey publicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_public_key.csr"));
-
- RSA rsa = new RSA(privateKey, publicKey);
- String str = "你好,Hutool";//测试字符串
-
- String encryptStr = rsa.encryptBase64(str, KeyType.PublicKey);
- String decryptStr = rsa.decryptStr(encryptStr, KeyType.PrivateKey);
- Assert.assertEquals(str, decryptStr);
- }
-
- @Test
- public void readECPrivateKeyTest() {
- PrivateKey privateKey = PemUtil.readSm2PemPrivateKey(ResourceUtil.getStream("test_ec_sec1_private_key.pem"));
- SM2 sm2 = new SM2(privateKey, null);
- sm2.usePlainEncoding();
-
- //需要签名的明文,得到明文对应的字节数组
- byte[] dataBytes = "我是一段测试aaaa".getBytes(StandardCharsets.UTF_8);
-
- byte[] sign = sm2.sign(dataBytes, null);
- // 64位签名
- Assert.assertEquals(64, sign.length);
- }
-
- @Test
- @Ignore
- public void readECPrivateKeyTest2() {
- // https://gitee.com/dromara/hutool/issues/I37Z75
- byte[] d = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/priv.key"));
- byte[] publicKey = PemUtil.readPem(FileUtil.getInputStream("d:/test/keys/pub.key"));
-
- SM2 sm2 = new SM2(d, publicKey);
- sm2.usePlainEncoding();
-
- String content = "我是Hanley.";
- byte[] sign = sm2.sign(StrUtil.utf8Bytes(content));
- boolean verify = sm2.verify(StrUtil.utf8Bytes(content), sign);
- Assert.assertTrue(verify);
- }
-
- @Test
- public void verifyPemUtilReadKey() {
- // 公钥
- // PKCS#10 文件读取公钥
- PublicKey csrPublicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_ec_certificate_request.csr"));
-
- // 证书读取公钥
- PublicKey certPublicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_ec_certificate.cer"));
-
- // PEM 公钥
- PublicKey plainPublicKey = PemUtil.readPemPublicKey(ResourceUtil.getStream("test_ec_public_key.pem"));
-
- // 私钥
- // 加密的 PEM 私钥
- PrivateKey encPrivateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_ec_encrypted_private_key.key"), "123456".toCharArray());
-
- // PKCS#8 私钥
- PrivateKey pkcs8PrivateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_ec_pkcs8_private_key.key"));
-
- // SEC 1 私钥
- PrivateKey sec1PrivateKey = PemUtil.readPemPrivateKey(ResourceUtil.getStream("test_ec_sec1_private_key.pem"));
-
- // 组装还原后的公钥和私钥列表
- List publicKeyList = Arrays.asList(csrPublicKey, certPublicKey, plainPublicKey);
- List privateKeyList = Arrays.asList(encPrivateKey, pkcs8PrivateKey, sec1PrivateKey);
-
- // 做笛卡尔积循环验证
- for (PrivateKey privateKeyItem : privateKeyList) {
- for (PublicKey publicKeyItem : publicKeyList) {
- // 校验公私钥
- SM2 genSm2 = new SM2(privateKeyItem, publicKeyItem);
- genSm2.usePlainEncoding();
-
- String content = "我是Hanley.";
- byte[] sign = genSm2.sign(StrUtil.utf8Bytes(content));
- boolean verify = genSm2.verify(StrUtil.utf8Bytes(content), sign);
- Assert.assertTrue(verify);
- }
- }
- }
-
-}