使用Java生成PKCS#1格式的RSA密钥

Ant*_*ony 21 java rsa x509 pkcs#1

当我使用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();
Run Code Online (Sandbox Code Playgroud)

两个结果字节数组的格式为X.509(公共)和PKCS#8(私有).

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

谢谢

Ale*_*kov 24

你需要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;
Run Code Online (Sandbox Code Playgroud)

下面的代码片段已经过检查,发现与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();
Run Code Online (Sandbox Code Playgroud)

将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();
Run Code Online (Sandbox Code Playgroud)

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

openssl rsa -in rsa_private_key.pem -noout -text
Run Code Online (Sandbox Code Playgroud)

公钥

将公钥从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();
Run Code Online (Sandbox Code Playgroud)

将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();
Run Code Online (Sandbox Code Playgroud)

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

openssl rsa -in rsa_public_key.pem -RSAPublicKey_in -noout -text
Run Code Online (Sandbox Code Playgroud)

谢谢

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

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

  • 很好的答案,拯救了我的一天 (2认同)

Sim*_*onJ 6

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

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

在哪里privateKey:

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

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

// 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.
Run Code Online (Sandbox Code Playgroud)


kla*_*her -1

BouncyCastle 框架有一个 PKCS1 编码器来解决这个问题:http://www.bouncycastle.org/docs/docs1.6/index.html