将 X509 Public 密钥转换为 RSA public 密钥
Convert a X509 Public key to RSA public key
我有一个 public 密钥,格式如下
-----BEGIN PUBLIC KEY-----
xxxxxxxx
-----END PUBLIC KEY-----
我需要把它转换成下面的格式
-----BEGIN RSA PUBLIC KEY-----
xxxxxxxxx
-----END RSA PUBLIC KEY-----
基本上,问题是我正在使用用 Java 编写的第三方库。
第三方库使用Javaclass"RSAPublicKeySpec"从String生成RSAPublicKey类型的实例。
我提供给第三方库的字符串取自格式如下的文件:
-----BEGIN PUBLIC KEY-----
xxxxxxxx
-----END PUBLIC KEY-----
- 稍微研究一下代码后,我发现如果我使用 java class "X509EncodedKeySpec" 加载这个 public 密钥,签名验证我的部分代码完美运行。但是,由于代码是第三方库,我无法更改他们代码中的 class 类型。我需要以某种方式确保我提供给库的输入与 "RSAPublicKeySpec" class 兼容,以便正确加载 public 密钥。
“RSA PUBLIC KEY”格式在很早的 SSLeay 中使用,它演变成 OpenSSL,但我相信在 2000 年之前就已经过时了,那是 Java 和我 think 在 Java 拥有 any 加密货币之前,即使是受限制的加密货币也允许从美国出口。简而言之,“RSA PUBLIC KEY”格式是来自 PKCS#1 的 RSA 特定格式,而“PUBLIC KEY”是处理众多(且可扩展)算法的 X.509 通用结构。因此,了解您的 Java 库的开发人员如何陷入这种奇怪的限制会很有趣。但无论如何...
尽管这种格式早已过时,OpenSSL 仍然支持它。如果你有可用的 openssl 命令行(可以在你复制 file/data 来回的另一个系统上)就这样做:
openssl rsa -in publickey.pem -out rsapublickey.pem -pubin -RSAPublicKey_out
啊! 写完下面的内容后,现在我注意到 Generating RSA keys in PKCS#1 format in Java 处的(更一般的)骗局
(加上从那里开始的几个链接)如果你在 Java 中使用 BouncyCastle(或在 C 中使用 OpenSSL 库,但你已经有上面的 OpenSSL 命令行选项)。
无论如何,如果您愿意,这里有两种在 普通 Java 中编码的概述:
它们都首先将输入 PEM 转换为字节。阅读“----BEGIN”行并最好检查它是否正确;阅读所有以下(base64 的)行,但不包括“-----END”行;将 base64 连接并解码为字节。 Java8提供java.util.Base64
;在此之前,您必须 fiddle 使用“内部” 类 或添加几个常见(但不是内置)库之一,如 commons-codecs 或自己编写(这并不难)。现在选择第 1 步或第 2 步。
解析那些字节作为ASN.1 DER encoding of an X.509 SubjectPublicKeyInfo as shown in RFC 5280 including the AlgorithmIdentifier。准确的说:跳过外层序列的标签和长度;跳过 AlgorithmIdentifier 的标签、长度和内容——或者更好地提取内容并检查它是 rsaEncryption 和 NULL(或可能省略)参数的 OID 的序列;然后跳过 BIT STRING 的标签和长度以及第一个字节(未使用的位),并将(剩余的)contents 作为编码密钥 - - 这已经是您想要的 PKCS#1 RSAPublicKey 结构。继续执行步骤 3。
或使用标准 JCE 读取 X.509 格式 密钥:将字节包装在 X509EncodedKeySpec
,将它交给 KeyFactory
的 .generatePublic()
for RSA,并将结果转换为 RSAPublicKey
。然后调用 .getModulus()
和 .getPublicExponent()
以 获取数学值并将它们 编码为结构 RSAPublicKey defined in PKCS#1 rfc3447 的 ASN.1 DER(用于 PKIX/X.509 在 rfc3279 2.2.1). BigInteger.toByteArray()
给出了 ASN.1 想要的 big-endian 带符号二进制补码形式,因此它包括:
获取两个 .toByteArray()
值,为每个值添加 tag=INTEGER (0x02) 和长度前缀,然后在它们的串联中添加 tag=SEQUENCE-composite (0x30) 和长度前缀。然后进行第3步。
现在你有了构成 PKCS#1 RSAPublicKey 的字节,转换为 PEM:编码为 base64;如果需要,或者为了安全起见,分成几行(64 个字符);并添加“BEGIN”和“END”行,除非不需要。
我有一个 public 密钥,格式如下
-----BEGIN PUBLIC KEY-----
xxxxxxxx
-----END PUBLIC KEY-----
我需要把它转换成下面的格式
-----BEGIN RSA PUBLIC KEY-----
xxxxxxxxx
-----END RSA PUBLIC KEY-----
基本上,问题是我正在使用用 Java 编写的第三方库。
第三方库使用Javaclass"RSAPublicKeySpec"从String生成RSAPublicKey类型的实例。
我提供给第三方库的字符串取自格式如下的文件:
-----BEGIN PUBLIC KEY-----
xxxxxxxx
-----END PUBLIC KEY-----
- 稍微研究一下代码后,我发现如果我使用 java class "X509EncodedKeySpec" 加载这个 public 密钥,签名验证我的部分代码完美运行。但是,由于代码是第三方库,我无法更改他们代码中的 class 类型。我需要以某种方式确保我提供给库的输入与 "RSAPublicKeySpec" class 兼容,以便正确加载 public 密钥。
“RSA PUBLIC KEY”格式在很早的 SSLeay 中使用,它演变成 OpenSSL,但我相信在 2000 年之前就已经过时了,那是 Java 和我 think 在 Java 拥有 any 加密货币之前,即使是受限制的加密货币也允许从美国出口。简而言之,“RSA PUBLIC KEY”格式是来自 PKCS#1 的 RSA 特定格式,而“PUBLIC KEY”是处理众多(且可扩展)算法的 X.509 通用结构。因此,了解您的 Java 库的开发人员如何陷入这种奇怪的限制会很有趣。但无论如何...
尽管这种格式早已过时,OpenSSL 仍然支持它。如果你有可用的 openssl 命令行(可以在你复制 file/data 来回的另一个系统上)就这样做:
openssl rsa -in publickey.pem -out rsapublickey.pem -pubin -RSAPublicKey_out
啊! 写完下面的内容后,现在我注意到 Generating RSA keys in PKCS#1 format in Java 处的(更一般的)骗局 (加上从那里开始的几个链接)如果你在 Java 中使用 BouncyCastle(或在 C 中使用 OpenSSL 库,但你已经有上面的 OpenSSL 命令行选项)。
无论如何,如果您愿意,这里有两种在 普通 Java 中编码的概述:
它们都首先将输入 PEM 转换为字节。阅读“----BEGIN”行并最好检查它是否正确;阅读所有以下(base64 的)行,但不包括“-----END”行;将 base64 连接并解码为字节。 Java8提供
java.util.Base64
;在此之前,您必须 fiddle 使用“内部” 类 或添加几个常见(但不是内置)库之一,如 commons-codecs 或自己编写(这并不难)。现在选择第 1 步或第 2 步。解析那些字节作为ASN.1 DER encoding of an X.509 SubjectPublicKeyInfo as shown in RFC 5280 including the AlgorithmIdentifier。准确的说:跳过外层序列的标签和长度;跳过 AlgorithmIdentifier 的标签、长度和内容——或者更好地提取内容并检查它是 rsaEncryption 和 NULL(或可能省略)参数的 OID 的序列;然后跳过 BIT STRING 的标签和长度以及第一个字节(未使用的位),并将(剩余的)contents 作为编码密钥 - - 这已经是您想要的 PKCS#1 RSAPublicKey 结构。继续执行步骤 3。
或使用标准 JCE 读取 X.509 格式 密钥:将字节包装在
X509EncodedKeySpec
,将它交给KeyFactory
的.generatePublic()
for RSA,并将结果转换为RSAPublicKey
。然后调用.getModulus()
和.getPublicExponent()
以 获取数学值并将它们 编码为结构 RSAPublicKey defined in PKCS#1 rfc3447 的 ASN.1 DER(用于 PKIX/X.509 在 rfc3279 2.2.1).BigInteger.toByteArray()
给出了 ASN.1 想要的 big-endian 带符号二进制补码形式,因此它包括: 获取两个.toByteArray()
值,为每个值添加 tag=INTEGER (0x02) 和长度前缀,然后在它们的串联中添加 tag=SEQUENCE-composite (0x30) 和长度前缀。然后进行第3步。现在你有了构成 PKCS#1 RSAPublicKey 的字节,转换为 PEM:编码为 base64;如果需要,或者为了安全起见,分成几行(64 个字符);并添加“BEGIN”和“END”行,除非不需要。