mirror of
				https://gitee.com/dromara/hutool.git
				synced 2025-10-31 16:36:56 +08:00 
			
		
		
		
	PemUtil.readPemPrivateKey支持pkcs#1格式,增加OpensslKeyUtil
This commit is contained in:
		| @@ -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) | ||||
|   | ||||
| @@ -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> | ||||
|   | ||||
							
								
								
									
										187
									
								
								hutool-crypto/src/main/java/cn/hutool/crypto/OpensslKeyUtil.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								hutool-crypto/src/main/java/cn/hutool/crypto/OpensslKeyUtil.java
									
									
									
									
									
										Normal 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()); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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 | ||||
| 	 */ | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cn.hutool.crypto.test; | ||||
| package cn.hutool.crypto; | ||||
| 
 | ||||
| import cn.hutool.crypto.BCUtil; | ||||
| import org.bouncycastle.crypto.params.ECPrivateKeyParameters; | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cn.hutool.crypto.test; | ||||
| package cn.hutool.crypto; | ||||
| 
 | ||||
| import cn.hutool.crypto.CryptoException; | ||||
| import cn.hutool.crypto.GlobalBouncyCastleProvider; | ||||
| @@ -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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @@ -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); | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -1,4 +1,4 @@ | ||||
| package cn.hutool.crypto.test; | ||||
| package cn.hutool.crypto; | ||||
| 
 | ||||
| import cn.hutool.core.util.CharsetUtil; | ||||
| import cn.hutool.crypto.KeyUtil; | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| @@ -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中文"; | ||||
| @@ -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; | ||||
| @@ -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 | ||||
|  * | ||||
|  */ | ||||
| @@ -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; | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| @@ -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); | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| 
 | ||||
| @@ -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; | ||||
| @@ -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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Looly
					Looly