From ba8b4ad760ba45eb82ff77ea4420531a816f2737 Mon Sep 17 00:00:00 2001 From: Looly Date: Fri, 26 Feb 2021 09:11:45 +0800 Subject: [PATCH] add methods --- .../main/java/cn/hutool/crypto/BCUtil.java | 37 ++++++++++ .../main/java/cn/hutool/crypto/PemUtil.java | 72 ++++++++++++++----- .../java/cn/hutool/crypto/asymmetric/SM2.java | 6 +- 3 files changed, 96 insertions(+), 19 deletions(-) diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/BCUtil.java b/hutool-crypto/src/main/java/cn/hutool/crypto/BCUtil.java index 918b1086b..1b603cc09 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/BCUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/BCUtil.java @@ -1,5 +1,8 @@ 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.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; import org.bouncycastle.crypto.params.ECDomainParameters; @@ -13,6 +16,7 @@ import org.bouncycastle.jce.spec.ECNamedCurveSpec; import org.bouncycastle.jce.spec.ECParameterSpec; import org.bouncycastle.math.ec.ECCurve; +import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.Key; @@ -313,4 +317,37 @@ public class BCUtil { public static PublicKey readPemPublicKey(InputStream pemStream) { return PemUtil.readPemPublicKey(pemStream); } + + /** + * Java中的PKCS#8格式私钥转换为OpenSSL支持的PKCS#1格式 + * + * @param privateKey PKCS#8格式私钥 + * @return PKCS#1格式私钥 + * @since 5.5.9 + */ + public static byte[] toPkcs1(PrivateKey privateKey){ + final PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded()); + try { + return pkInfo.parsePrivateKey().toASN1Primitive().getEncoded(); + } catch (IOException e) { + throw new IORuntimeException(e); + } + } + + /** + * Java中的X.509格式公钥转换为OpenSSL支持的PKCS#1格式 + * + * @param publicKey X.509格式公钥 + * @return PKCS#1格式公钥 + * @since 5.5.9 + */ + public static byte[] toPkcs1(PublicKey publicKey){ + final SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo + .getInstance(publicKey.getEncoded()); + try { + return spkInfo.parsePublicKey().getEncoded(); + } catch (IOException e) { + throw new IORuntimeException(e); + } + } } 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 5d9cb4b4f..5e3e29797 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/PemUtil.java @@ -13,6 +13,8 @@ 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.PublicKey; @@ -67,7 +69,8 @@ public class PemUtil { //private if (type.endsWith("EC PRIVATE KEY")) { return KeyUtil.generatePrivateKey("EC", object.getContent()); - }if (type.endsWith("PRIVATE KEY")) { + } + if (type.endsWith("PRIVATE KEY")) { return KeyUtil.generateRSAPrivateKey(object.getContent()); } @@ -130,11 +133,35 @@ public class PemUtil { } } + /** + * 读取OpenSSL生成的ANS1格式的Pem私钥文件 + * + * @param keyStream 私钥pem流 + * @return {@link PrivateKey} + */ + public static PrivateKey readSm2PemPrivateKey(InputStream keyStream) { + final ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(readPem(keyStream)); + return ECKeyUtil.toSm2PrivateKey(ecPrivateKey); + } + + /** + * 将私钥或公钥转换为PEM格式的字符串 + * @param type 密钥类型(私钥、公钥、证书) + * @param content 密钥内容 + * @return PEM内容 + * @since 5.5.9 + */ + public static String toPem(String type, byte[] content) { + final StringWriter stringWriter = new StringWriter(); + writePemObject(type, content, stringWriter); + return stringWriter.toString(); + } + /** * 写出pem密钥(私钥、公钥、证书) * * @param type 密钥类型(私钥、公钥、证书) - * @param content 密钥内容 + * @param content 密钥内容,需为PKCS#1格式 * @param keyStream pem流 * @since 5.1.6 */ @@ -142,6 +169,18 @@ public class PemUtil { writePemObject(new PemObject(type, content), keyStream); } + /** + * 写出pem密钥(私钥、公钥、证书) + * + * @param type 密钥类型(私钥、公钥、证书) + * @param content 密钥内容,需为PKCS#1格式 + * @param writer pemWriter + * @since 5.5.9 + */ + public static void writePemObject(String type, byte[] content, Writer writer) { + writePemObject(new PemObject(type, content), writer); + } + /** * 写出pem密钥(私钥、公钥、证书) * @@ -150,25 +189,24 @@ public class PemUtil { * @since 5.1.6 */ public static void writePemObject(PemObjectGenerator pemObject, OutputStream keyStream) { - PemWriter writer = null; - try { - writer = new PemWriter(IoUtil.getUtf8Writer(keyStream)); - writer.writeObject(pemObject); - } catch (IOException e) { - throw new IORuntimeException(e); - } finally { - IoUtil.close(writer); - } + writePemObject(pemObject, IoUtil.getUtf8Writer(keyStream)); } /** - * 读取OpenSSL生成的ANS1格式的Pem私钥文件 + * 写出pem密钥(私钥、公钥、证书) * - * @param keyStream 私钥pem流 - * @return {@link PrivateKey} + * @param pemObject pem对象,包括密钥和密钥类型等信息 + * @param writer pemWriter + * @since 5.5.9 */ - public static PrivateKey readSm2PemPrivateKey(InputStream keyStream){ - final ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(readPem(keyStream)); - return ECKeyUtil.toSm2PrivateKey(ecPrivateKey); + public static void writePemObject(PemObjectGenerator pemObject, Writer writer) { + final PemWriter pemWriter = new PemWriter(writer); + try { + pemWriter.writeObject(pemObject); + } catch (IOException e) { + throw new IORuntimeException(e); + } finally { + IoUtil.close(pemWriter); + } } } diff --git a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java index 8a26f5d95..ad4c3cf78 100644 --- a/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java +++ b/hutool-crypto/src/main/java/cn/hutool/crypto/asymmetric/SM2.java @@ -274,7 +274,8 @@ public class SM2 extends AbstractAsymmetricCrypto { } /** - * 用私钥对信息生成数字签名 + * 用私钥对信息生成数字签名,签名格式为ASN1
+ * * 在硬件签名中,返回结果为R+S,可以通过调用{@link cn.hutool.crypto.SmUtil#rsAsn1ToPlain(byte[])}方法转换之。 * * @param data 加密数据 * @return 签名 @@ -295,7 +296,8 @@ public class SM2 extends AbstractAsymmetricCrypto { } /** - * 用私钥对信息生成数字签名 + * 用私钥对信息生成数字签名,签名格式为ASN1
+ * 在硬件签名中,返回结果为R+S,可以通过调用{@link cn.hutool.crypto.SmUtil#rsAsn1ToPlain(byte[])}方法转换之。 * * @param data 被签名的数据数据 * @param id 可以为null,若为null,则默认withId为字节数组:"1234567812345678".getBytes()