在 Java 中生成 PKCS#1 格式的 RSA 密钥

2022-09-01 17:21:31

当我使用 Java API 生成 RSA 密钥对时,公钥以 X.509 格式编码,私钥以 PKCS#8 格式编码。我希望将两者都编码为PKCS#1。这可能吗?我花了相当多的时间浏览Java文档,但还没有找到解决方案。当我使用Java和Bouncy Castle提供程序时,结果是相同的。

下面是代码的一个片段:

KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA","BC");
keygen.initialize(1024);
KeyPair pair = keygen.generateKeyPair();
PrivateKey priv = pair.getPrivate();
PublicKey pub = pair.getPublic();
byte[] privBytes = priv.getEncoded();
byte[] pubBytes = pub.getEncoded();

生成的两个字节数组的格式为 X.509(公共)和 PKCS#8(专用)。

任何帮助将不胜感激。有一些类似的帖子,但没有一个真正回答我的问题。

谢谢


答案 1

您将需要BouncyCastle:

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

下面的代码片段已经过检查,发现可以与Bouncy Castle 1.52配合使用。

私钥

将私钥从 PKCS8 转换为 PKCS1:

PrivateKey priv = pair.getPrivate();
byte[] privBytes = priv.getEncoded();

PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);
ASN1Encodable encodable = pkInfo.parsePrivateKey();
ASN1Primitive primitive = encodable.toASN1Primitive();
byte[] privateKeyPKCS1 = primitive.getEncoded();

将 PKCS1 中的私钥转换为 PEM:

PemObject pemObject = new PemObject("RSA PRIVATE KEY", privateKeyPKCS1);
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.writeObject(pemObject);
pemWriter.close();
String pemString = stringWriter.toString();

使用命令行 OpenSSL 检查密钥格式是否符合预期:

openssl rsa -in rsa_private_key.pem -noout -text

公钥

将公钥从 X.509 SubjectPublicKeyInfo 转换为 PKCS1:

PublicKey pub = pair.getPublic();
byte[] pubBytes = pub.getEncoded();

SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
ASN1Primitive primitive = spkInfo.parsePublicKey();
byte[] publicKeyPKCS1 = primitive.getEncoded();

将 PKCS1 中的公钥转换为 PEM:

PemObject pemObject = new PemObject("RSA PUBLIC KEY", publicKeyPKCS1);
StringWriter stringWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(stringWriter);
pemWriter.writeObject(pemObject);
pemWriter.close();
String pemString = stringWriter.toString();

使用命令行 OpenSSL 检查密钥格式是否符合预期:

openssl rsa -in rsa_public_key.pem -RSAPublicKey_in -noout -text

谢谢

非常感谢以下帖子的作者:

这些帖子包含有用的,但不完整的,有时过时的信息(即旧版本的BouncyCastle),这有助于我构建这篇文章。


答案 2

RFC5208 开始,PKCS#8 未加密格式由一个结构组成:PrivateKeyInfo

PrivateKeyInfo ::= SEQUENCE {
  version                   Version,
  privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
  privateKey                PrivateKey,
  attributes           [0]  IMPLICIT Attributes OPTIONAL }

在哪里:privateKey

"...一个八位字节字符串,其内容是私钥的值。内容的解释在私钥算法的注册中定义。例如,对于 RSA 私钥,内容是 RSAPrivateKey 类型的值的 BER 编码。

此结构只是密钥的 PKCS#1 编码,我们可以使用 BouncyCastle 提取它:RSAPrivateKey

// pkcs8Bytes contains PKCS#8 DER-encoded key as a byte[]
PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes);
RSAPrivateKeyStructure pkcs1Key = RSAPrivateKeyStructure.getInstance(
        pki.getPrivateKey());
byte[] pkcs1Bytes = pkcs1Key.getEncoded(); // etc.

推荐