PemUtil.readPemPrivateKey支持pkcs#1格式,增加OpensslKeyUtil

This commit is contained in:
Looly 2022-07-17 21:26:09 +08:00
parent b6a4be4aab
commit 5ba2ba9e2a
30 changed files with 411 additions and 294 deletions

View File

@ -21,6 +21,7 @@
* 【core 】 增加TemporalAccessorUtil.isIn、LocalDateTimeUtil.isInissue#I5HBL0@Gitee
* 【core 】 ReUtil增加getAllGroups重载pr#2455@Github
* 【core 】 PageUtil#totalPage增加totalCount为long类型的重载方法pr#2442@Github
* 【crypto 】 PemUtil.readPemPrivateKey支持pkcs#1格式增加OpensslKeyUtilpr#2456@Github
*
### 🐞Bug修复
* 【core 】 修复CollUtil里面关于可变参数传null造成的crash问题pr#2428@Github

View File

@ -18,7 +18,7 @@
<properties>
<!-- versions -->
<bouncycastle.version>1.70</bouncycastle.version>
<bouncycastle.version>1.71</bouncycastle.version>
</properties>
<dependencies>
@ -29,14 +29,7 @@
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<artifactId>bcpkix-jdk15to18</artifactId>
<version>${bouncycastle.version}</version>
<scope>compile</scope>
<optional>true</optional>

View File

@ -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密钥文件读取等<br>
* 注意此工具需要引入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文件中读取公钥或私钥<br>
* 根据类型返回 {@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文件中的密钥密钥支持包括<br>
* <ul>
* <li>{@link PrivateKeyInfo}</li>
* <li>{@link PEMKeyPair}默认读取私钥</li>
* <li>{@link PKCS8EncryptedPrivateKeyInfo}</li>
* <li>{@link PEMEncryptedKeyPair}默认读取私钥</li>
* <li>{@link X509CertificateHolder}</li>
* <li>{@link X509TrustedCertificateBlock}</li>
* <li>{@link PKCS10CertificationRequest}</li>
* </ul>
*
* @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());
}
}
}

View File

@ -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文件中读取公钥或私钥<br/>
* 根据类型返回 {@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
*/

View File

@ -1,4 +1,4 @@
package cn.hutool.crypto.test;
package cn.hutool.crypto;
import cn.hutool.crypto.BCUtil;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;

View File

@ -1,4 +1,4 @@
package cn.hutool.crypto.test;
package cn.hutool.crypto;
import cn.hutool.crypto.CryptoException;
import cn.hutool.crypto.GlobalBouncyCastleProvider;

View File

@ -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<PublicKey> publicKeyList = Arrays.asList(csrPublicKey, certPublicKey, plainPublicKey);
final List<PrivateKey> 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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -1,4 +1,4 @@
package cn.hutool.crypto.test;
package cn.hutool.crypto;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.crypto.KeyUtil;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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中文";

View File

@ -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;

View File

@ -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
*
*/

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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<PublicKey> publicKeyList = Arrays.asList(csrPublicKey, certPublicKey, plainPublicKey);
List<PrivateKey> 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);
}
}
}
}