如何在两种公钥格式之间进行转换,一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY”

Posted

技术标签:

【中文标题】如何在两种公钥格式之间进行转换,一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY”【英文标题】:How can I transform between the two styles of public key format, one "BEGIN RSA PUBLIC KEY", the other is "BEGIN PUBLIC KEY" 【发布时间】:2013-08-05 01:15:53 【问题描述】:

如何在两种公钥格式之间进行转换, 一种格式是:

-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----

另一种格式是:

-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----

例如,我使用 ssh-keygen 命令生成了 id_rsa/id_rsa.pub 对, 我使用 id_rsa 计算了公钥:

openssl rsa -in id_rsa -pubout -out pub2 

然后我再次使用 id_rsa.pub 计算了公钥:

ssh-keygen -f id_rsa.pub -e -m pem > pub1

内容是 pub1 是:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END RSA PUBLIC KEY-----

pub2 的内容是:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61BjmfXGEvWmegnBGSuS
+rU9soUg2FnODva32D1AqhwdziwHINFaD1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBS
EVCgJjtHAGZIm5GL/KA86KDp/CwDFMSwluowcXwDwoyinmeOY9eKyh6aY72xJh7n
oLBBq1N0bWi1e2i+83txOCg4yV2oVXhBo8pYEJ8LT3el6Smxol3C1oFMVdwPgc0v
Tl25XucMcG/ALE/KNY6pqC2AQ6R2ERlVgPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeu
lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
ZQIDAQAB
-----END PUBLIC KEY-----

据我了解,pub1 和 pub2 包含相同的公钥信息,但它们的格式不同,我想知道如何在这两种格式之间进行转换?谁能给我简要介绍一下拖车格式?

【问题讨论】:

Stack Overflow 是一个编程和开发问题的网站。这个问题似乎离题了,因为它与编程或开发无关。请参阅帮助中心的What topics can I ask about here。也许Super User 或Unix & Linux Stack Exchange 会是一个更好的提问地点。 【参考方案1】:

使用phpseclib, a pure PHP RSA implementation...

<?php
include('Crypt/RSA.php');

$rsa = new Crypt_RSA();
$rsa->loadKey('-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61BjmfXGEvWmegnBGSuS
+rU9soUg2FnODva32D1AqhwdziwHINFaD1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBS
EVCgJjtHAGZIm5GL/KA86KDp/CwDFMSwluowcXwDwoyinmeOY9eKyh6aY72xJh7n
oLBBq1N0bWi1e2i+83txOCg4yV2oVXhBo8pYEJ8LT3el6Smxol3C1oFMVdwPgc0v
Tl25XucMcG/ALE/KNY6pqC2AQ6R2ERlVgPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeu
lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
ZQIDAQAB
-----END PUBLIC KEY-----');
$rsa->setPublicKey();

echo $rsa->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW);

即使标头显示 BEGIN PUBLIC KEY 而不是 BEGIN RSA PUBLIC KEY,base64 编码的内容似乎也匹配。所以也许只是使用 str_replace 来解决这个问题,你应该很高兴!

【讨论】:

【参考方案2】:

除了页眉/页脚之外,您的 pub1 和 pub2 之间的唯一区别是 pub2 中的这个附加字符串:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A。如果删除它,Base 64 与 pub1 中的相同。

多余的字符串对应this Answer的算法标识符。

【讨论】:

【参考方案3】:

我发现这个网站是对不同格式的一个很好的技术解释:https://polarssl.org/kb/cryptography/asn1-key-structures-in-der-and-pem

“BEGIN RSA PUBLIC KEY”为PKCS#1,只能包含RSA密钥。

“BEGIN PUBLIC KEY”是PKCS#8,可以包含多种格式。

如果你只是想用命令行转换它们,“openssl rsa”很适合。

从 PKCS#8 转换为 PKCS#1:

openssl rsa -pubin -in <filename> -RSAPublicKey_out

从 PKCS#1 转换为 PKCS#8:

openssl rsa -RSAPublicKey_in -in <filename> -pubout

【讨论】:

我在 PKCS#8 (RFC 5208) 中找不到任何关于公钥的信息。 不适用于 MacOS:unknown option -RSAPublicKey_in @FranklinYu:是的,PKCS8 只是私钥,并且在这一点上 polarssl 是错误的。 publickey 的通用形式由 X.509 定义,特别是 SubjectPublicKeyInfo 类型,正如 Ian Boyd 的(长!)答案中正确说明的那样;此信息(更方便)在 RFC5280 和其他 RFC 中重复,具体取决于算法,在 RFC3279 中使用“基本”RSA。 @nakajuice:您需要 OpenSSL 版本 1.0.0(2010 年发布)或更高版本。 AIUI Apple 停止在 OS(X) 上支持 OpenSSL,因此您可能需要 brew 或类似版本的版本。 这让我找到了从 OpenSSH 格式转换的正确方向。我最终像这样使用 ssh-keygen: ssh-keygen -i -f ~/.ssh/id_rsa.pub -e -m PKCS8 > ~/.ssh/id_rsa.pub.pem【参考方案4】:

我想帮助解释这里发生了什么。

RSA“公钥”由两个数字组成:

模数(例如 2,048 位数) 指数(通常为 65,537)

以您的 RSA 公钥为例,这两个数字是:

模数:297,056,429,939,040,947,991,047,334,197,581,225,628,107,021,573,849,359,042,679,698 ,093,131,908,015,712,695,688,944,173,317,630,555,849,768,647,118,986,535,684,992,447,654,339,728,777 ,985,990,170,679,511,111,819,558,063,246,667,855,023,730,127,805,401,069,042,322,764,200,545,883,378 ,826,983,730,553,730,138,478,384,327,116,513,143,842,816,383,440,639,376,515,039,682,874,046,227,217,032,079,079,790,098,143,158,087,443,017,552,531,393,264,852,461,292,775,129,262,080,851,633,535,934,010,704,122,673,027,067,442,627,059,982,393,297,716,922,243,940,155,855,127,430,302,323,883,824,137,412,883,916,794,359,982,603,439,112,095,116,831,297,809,626,059,569,444,750,808,699,678,211,904,501,083,183,234,323,797,142,810,155,862,553,705,570,600,021,649,944,369,726,123,996,534,870,137,000,784,980,673,984,909,570,977,377,882,585,701 LI> 指数:65,537

那么问题就变成了我们要如何将这些数字存储在计算机中。首先我们将两者都转换为十六进制:

模量强>:EB506399F5C612F5A67A09C1192B92FAB53DB28520D859CE0EF6B7D83D40AA1C1DCE2C0720D15A0F531595CAD81BA5D129F91CC6769719F1435872C4BCD0521150A0263B470066489B918BFCA03CE8A0E9FC2C0314C4B096EA30717C03C28CA29E678E63D78ACA1E9A63BDB1261EE7A0B041AB53746D68B57B68BEF37B71382838C95DA8557841A3CA58109F0B4F77A5E929B1A25DC2D6814C55DC0F81CD2F4E5DB95EE70C706FC02C4FCA358EA9A82D8043A47611195580F89458E3DAB5592DEFE06CDE1E516A6C61ED78C13977AE9660A9192CA75CD72967FD3AFAFA1F1A2FF6325A5064D847028F1E6B2329E8572F36E708A549DDA355FC74A32FDD8DBA65 LI> 指数:010001

RSA 发明了第一种格式

RSA首先发明了一种格式:

RSAPublicKey ::= SEQUENCE 
    modulus           INTEGER,  -- n
    publicExponent    INTEGER   -- e

他们选择使用 ASN.1 二进制编码标准的 DER 风格来表示两个数字[1]:

SEQUENCE (2 elements)
   INTEGER (2048 bit): EB506399F5C612F5A67A09C1192B92FAB53DB28520D859CE0EF6B7D83D40AA1C1DCE2C0720D15A0F531595CAD81BA5D129F91CC6769719F1435872C4BCD0521150A0263B470066489B918BFCA03CE8A0E9FC2C0314C4B096EA30717C03C28CA29E678E63D78ACA1E9A63BDB1261EE7A0B041AB53746D68B57B68BEF37B71382838C95DA8557841A3CA58109F0B4F77A5E929B1A25DC2D6814C55DC0F81CD2F4E5DB95EE70C706FC02C4FCA358EA9A82D8043A47611195580F89458E3DAB5592DEFE06CDE1E516A6C61ED78C13977AE9660A9192CA75CD72967FD3AFAFA1F1A2FF6325A5064D847028F1E6B2329E8572F36E708A549DDA355FC74A32FDD8DBA65
   INTEGER (24 bit): 010001

ASN.1中最终的二进制编码为:

30 82 01 0A      ;sequence (0x10A bytes long)
   02 82 01 01   ;integer (0x101 bytes long)
      00 EB506399F5C612F5A67A09C1192B92FAB53DB28520D859CE0EF6B7D83D40AA1C1DCE2C0720D15A0F531595CAD81BA5D129F91CC6769719F1435872C4BCD0521150A0263B470066489B918BFCA03CE8A0E9FC2C0314C4B096EA30717C03C28CA29E678E63D78ACA1E9A63BDB1261EE7A0B041AB53746D68B57B68BEF37B71382838C95DA8557841A3CA58109F0B4F77A5E929B1A25DC2D6814C55DC0F81CD2F4E5DB95EE70C706FC02C4FCA358EA9A82D8043A47611195580F89458E3DAB5592DEFE06CDE1E516A6C61ED78C13977AE9660A9192CA75CD72967FD3AFAFA1F1A2FF6325A5064D847028F1E6B2329E8572F36E708A549DDA355FC74A32FDD8DBA65
   02 03         ;integer (3 bytes long)
      010001

如果您将所有这些字节一起运行并进行 Base64 编码,您会得到:

MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB

RSA 实验室然后说添加标题和尾部:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END RSA PUBLIC KEY-----

五个连字符和单词BEGIN RSA PUBLIC KEY。那是您的 PEM DER ASN.1 PKCS#1 RSA 公钥

PEM:base64 的同义词 DER:ASN.1 编码的一种风格 ASN.1:使用的二进制编码方案 PKCS#1:正式规范,规定将公钥表示为由模数后跟指数组成的结构 RSA 公钥:正在使用的公钥算法

不仅仅是 RSA

此后,出现了其他形式的公钥加密:

迪菲-赫尔曼 椭圆曲线

当需要为如何表示那些加密算法的参数创建一个标准时,人们采用了许多与 RSA 最初定义的相同的想法:

使用 ASN.1 二进制编码 base64吧 用五个连字符括起来 和BEGIN PUBLIC KEY这几个字

但不是使用:

-----BEGIN RSA PUBLIC KEY----- -----BEGIN DH PUBLIC KEY----- -----BEGIN EC PUBLIC KEY-----

他们决定改为包含后续内容的对象标识符 (OID)。对于 RSA 公钥,即:

RSA PKCS#11.2.840.113549.1.1.1

所以对于 RSA 公钥,它本质上是:

public struct RSAPublicKey 
   INTEGER modulus,
   INTEGER publicExponent 

现在他们创建了 SubjectPublicKeyInfo,基本上是:

public struct SubjectPublicKeyInfo 
   AlgorithmIdentifier algorithm,
   RSAPublicKey subjectPublicKey

在实际的 DER ASN.1 中定义为:

SubjectPublicKeyInfo  ::=  SEQUENCE  
    algorithm  ::=  SEQUENCE  
        algorithm               OBJECT IDENTIFIER, -- 1.2.840.113549.1.1.1 rsaEncryption (PKCS#1 1)
        parameters              ANY DEFINED BY algorithm OPTIONAL  ,
    subjectPublicKey     BIT STRING 
        RSAPublicKey ::= SEQUENCE 
            modulus            INTEGER,    -- n
            publicExponent     INTEGER     -- e
        

这会给你一个 ASN.1:

SEQUENCE (2 elements)
   SEQUENCE (2 elements)
      OBJECT IDENTIFIER 1.2.840.113549.1.1.1
      NULL
   BIT STRING (1 element)
      SEQUENCE (2 elements)
         INTEGER (2048 bit): EB506399F5C612F5A67A09C1192B92FAB53DB28520D859CE0EF6B7D83D40AA1C1DCE2C0720D15A0F531595CAD81BA5D129F91CC6769719F1435872C4BCD0521150A0263B470066489B918BFCA03CE8A0E9FC2C0314C4B096EA30717C03C28CA29E678E63D78ACA1E9A63BDB1261EE7A0B041AB53746D68B57B68BEF37B71382838C95DA8557841A3CA58109F0B4F77A5E929B1A25DC2D6814C55DC0F81CD2F4E5DB95EE70C706FC02C4FCA358EA9A82D8043A47611195580F89458E3DAB5592DEFE06CDE1E516A6C61ED78C13977AE9660A9192CA75CD72967FD3AFAFA1F1A2FF6325A5064D847028F1E6B2329E8572F36E708A549DDA355FC74A32FDD8DBA65
         INTEGER (24 bit): 010001

ASN.1中最终的二进制编码为:

30 82 01 22          ;SEQUENCE (0x122 bytes = 290 bytes)
|  30 0D             ;SEQUENCE (0x0d bytes = 13 bytes) 
|  |  06 09          ;OBJECT IDENTIFIER (0x09 = 9 bytes)
|  |  2A 86 48 86   
|  |  F7 0D 01 01 01 ;hex encoding of 1.2.840.113549.1.1
|  |  05 00          ;NULL (0 bytes)
|  03 82 01 0F 00    ;BIT STRING  (0x10f = 271 bytes)
|  |  30 82 01 0A       ;SEQUENCE (0x10a = 266 bytes)
|  |  |  02 82 01 01    ;INTEGER  (0x101 = 257 bytes)
|  |  |  |  00             ;leading zero of INTEGER
|  |  |  |  EB 50 63 99 F5 C6 12 F5  A6 7A 09 C1 19 2B 92 FA 
|  |  |  |  B5 3D B2 85 20 D8 59 CE  0E F6 B7 D8 3D 40 AA 1C 
|  |  |  |  1D CE 2C 07 20 D1 5A 0F  53 15 95 CA D8 1B A5 D1 
|  |  |  |  29 F9 1C C6 76 97 19 F1  43 58 72 C4 BC D0 52 11 
|  |  |  |  50 A0 26 3B 47 00 66 48  9B 91 8B FC A0 3C E8 A0
|  |  |  |  E9 FC 2C 03 14 C4 B0 96  EA 30 71 7C 03 C2 8C A2  
|  |  |  |  9E 67 8E 63 D7 8A CA 1E  9A 63 BD B1 26 1E E7 A0  
|  |  |  |  B0 41 AB 53 74 6D 68 B5  7B 68 BE F3 7B 71 38 28
|  |  |  |  38 C9 5D A8 55 78 41 A3  CA 58 10 9F 0B 4F 77 A5
|  |  |  |  E9 29 B1 A2 5D C2 D6 81  4C 55 DC 0F 81 CD 2F 4E 
|  |  |  |  5D B9 5E E7 0C 70 6F C0  2C 4F CA 35 8E A9 A8 2D 
|  |  |  |  80 43 A4 76 11 19 55 80  F8 94 58 E3 DA B5 59 2D
|  |  |  |  EF E0 6C DE 1E 51 6A 6C  61 ED 78 C1 39 77 AE 96 
|  |  |  |  60 A9 19 2C A7 5C D7 29  67 FD 3A FA FA 1F 1A 2F 
|  |  |  |  F6 32 5A 50 64 D8 47 02  8F 1E 6B 23 29 E8 57 2F 
|  |  |  |  36 E7 08 A5 49 DD A3 55  FC 74 A3 2F DD 8D BA 65
|  |  |  02 03          ;INTEGER (03 = 3 bytes)
|  |  |  |  010001
   

和以前一样,您获取所有这些字节,对它们进行 Base64 编码,最终得到第二个示例:

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61BjmfXGEvWmegnBGSuS
+rU9soUg2FnODva32D1AqhwdziwHINFaD1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBS
EVCgJjtHAGZIm5GL/KA86KDp/CwDFMSwluowcXwDwoyinmeOY9eKyh6aY72xJh7n
oLBBq1N0bWi1e2i+83txOCg4yV2oVXhBo8pYEJ8LT3el6Smxol3C1oFMVdwPgc0v
Tl25XucMcG/ALE/KNY6pqC2AQ6R2ERlVgPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeu
lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
ZQIDAQAB   

添加稍微不同的页眉和尾声,你会得到:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61BjmfXGEvWmegnBGSuS
+rU9soUg2FnODva32D1AqhwdziwHINFaD1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBS
EVCgJjtHAGZIm5GL/KA86KDp/CwDFMSwluowcXwDwoyinmeOY9eKyh6aY72xJh7n
oLBBq1N0bWi1e2i+83txOCg4yV2oVXhBo8pYEJ8LT3el6Smxol3C1oFMVdwPgc0v
Tl25XucMcG/ALE/KNY6pqC2AQ6R2ERlVgPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeu
lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
ZQIDAQAB   
-----END PUBLIC KEY-----

这是您的 X.509 SubjectPublicKeyInfo/OpenSSL PEM 公钥 [2]。

做对了,或者破解它

既然您知道编码并不神奇,您可以编写解析出 RSA 模数和指数所需的所有部分。或者您可以认识到前 24 个字节只是在原始 PKCS#1 标准之上添加的新内容

30 82 01 22          ;SEQUENCE (0x122 bytes = 290 bytes)
|  30 0D             ;SEQUENCE (0x0d bytes = 13 bytes) 
|  |  06 09          ;OBJECT IDENTIFIER (0x09 = 9 bytes)
|  |  2A 86 48 86   
|  |  F7 0D 01 01 01 ;hex encoding of 1.2.840.113549.1.1
|  |  05 00          ;NULL (0 bytes)
|  03 82 01 0F 00    ;BIT STRING  (0x10f = 271 bytes)
|  |  ...

前 24 字节是 “新” 添加的内容:

30 82 01 22 30 0D 06 09 2A 86 48 86 F7 0D 01 01 01 05 00 03 82 01 0F 00

由于幸运和好运的非凡巧合:

24 个字节恰好恰好对应 32 个 base64 编码字符

因为在Base64中:3个字节变成了四个字符:

30 82 01  22 30 0D  06 09 2A  86 48 86  F7 0D 01  01 01 05  00 03 82  01 0F 00
\______/  \______/  \______/  \______/  \______/  \______/  \______/  \______/
    |         |         |         |         |         |         |         |
  MIIB      IjAN      Bgkq      hkiG      9w0B      AQEF      AAOC      AQ8A

这意味着如果您使用第二个 X.509 公钥,前 32 个字符仅对应于新添加的内容:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END PUBLIC KEY-----

如果您删除前 32 个字符,并将其更改为 BEGIN RSA PUBLIC KEY

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
-----END RSA PUBLIC KEY-----

你有你想要的——旧的RSA PUBLIC KEY格式。

【讨论】:

天哪,这信息量很大!谢谢。这解决了我与一个只期待 BEGIN RSA PUBLIC KEY 的 python 人的问题。不过,在您的上一个示例中,您似乎忘记删除 32 个字符。 @Buge 我使用了优秀的,优秀的,ASN.1 javascript decoder。那和TRANSLATOR, BINARY 是您的技巧工具箱中的两个出色工具。 模数的开头有一个额外的“1”字符。它应该开始如此...... 297,056,429,939,040,947,581,225,628,1991,225,628,1991,225,628,107,02,573 ......但不是这个...... 297,056,429,939,040,97,581,047,334,197,581,573 ...希望能帮助某种人对他们的十六进制转换生气。 span> jsFiddle version of ASN.1 js。它也在github INTEGER (12 bit): 010001: 不应该是 24 吗? 010001 是 24 位,65537 不适合 12 位。【参考方案5】:

虽然上述关于 32 字节标头、OID 格式等的 cmets 很有趣,但我个人认为没有相同的行为,假设我明白了这一点。我认为在大多数人可能认为过多的细节中进一步探索这一点可能会有所帮助。没有什么比多余的了。

首先,我创建了一个 RSA 私钥,并检查了它:

>openssl rsa -in newclient_privatekey.pem  -check
RSA key ok
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCn/OlFk7vLRQ6dBiNQkvjnhm4pOYWo+GeAEmU4N1HPZj1dxv70
4hm80eYc7h12xc7oVcDLBdHByGAGBpQfpjgdPyozC/zSqcuU6iBrvzDTpyG1zhIG
76KrcjdbX6PlKAPO9r/dCRmUijFhVoUlY6ywGknmLBrtZkLkBhchgYnMswIDAQAB
AoGAQaJ5aivspeEXcpahWavzAFLv27+Tz48usUV+stY6arRhqbBEkV19/N5t8EPA
01U6IGDQ8QIXEIW/rtsHKM6DAZhAbakPDJhJRatcMzJ08ryIkP/c3+onkTquiveG
brw7xzn6Xa8ls04aQ6VQR4jxXUjV5bB72pFZnGRoAmS2NiECQQDUoISbmTGjnHM+
kEfunNTXbNmKklwTYhyZaSVsSptnD7CvLWB4qB/g4h2/HjsELag6Z7SlWuYr7tba
H3nBYn35AkEAykFRudMqlBy3XmcGIpjxOD+7huyViPoUpy3ui/Bj3GbqsbEAt9cR
PyOJa1VFa2JqShta1Tdep8LJv1QvgvY7CwJBAML+al5gAXvwEGhB3RXg0fi2JFLG
opZMFbpDCUTkrtu3MeuVC7HbTVDpTSpmSO0uCed2D97NG+USZgsnbnuBHdECQQCw
S3FWPXdetQ0srzaMz61rLzphaDULuZhpBMNqnTYeNmMaUcPjewagd3Rf52rkKFun
juKE+Yd7SXGbYWEskT5zAkAD7tbNwe5ryD2CT71jrY/5uXMR2yg/A4Ry2ocZkQUp
iGflLrHnODvHO5LYLBlSKpjanBceYHJLuMFNZruf7uBM
-----END RSA PRIVATE KEY-----

(哦,太可怕了!我暴露了一个私钥。嗯……)

我提取并显示它的公钥:

>openssl rsa -in newclient_privatekey.pem -pubout
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn/OlFk7vLRQ6dBiNQkvjnhm4p
OYWo+GeAEmU4N1HPZj1dxv704hm80eYc7h12xc7oVcDLBdHByGAGBpQfpjgdPyoz
C/zSqcuU6iBrvzDTpyG1zhIG76KrcjdbX6PlKAPO9r/dCRmUijFhVoUlY6ywGknm
LBrtZkLkBhchgYnMswIDAQAB
-----END PUBLIC KEY-----

碰巧还有另一个公钥输出参数(如前面的评论中所述)。我改为使用该关键字提取并显示公钥:

>openssl rsa -in newclient_privatekey.pem -RSAPublicKey_out
writing RSA key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKf86UWTu8tFDp0GI1CS+OeGbik5haj4Z4ASZTg3Uc9mPV3G/vTiGbzR
5hzuHXbFzuhVwMsF0cHIYAYGlB+mOB0/KjML/NKpy5TqIGu/MNOnIbXOEgbvoqty
N1tfo+UoA872v90JGZSKMWFWhSVjrLAaSeYsGu1mQuQGFyGBicyzAgMBAAE=
-----END RSA PUBLIC KEY-----

好吧,好吧。这两个公钥值不相同,尽管它们是从同一个私钥派生的。或者他们是一样的?我将两个公钥字符串剪切并粘贴到它们自己的文件中,然后对每个字符串进行模数检查:

>openssl rsa -in newclient_publickey.pem -pubin -modulus
Modulus=
A7FCE94593BBCB450E9D06235092F8E7
866E293985A8F867801265383751CF66
3D5DC6FEF4E219BCD1E61CEE1D76C5CE
E855C0CB05D1C1C8600606941FA6381D
3F2A330BFCD2A9CB94EA206BBF30D3A7
21B5CE1206EFA2AB72375B5FA3E52803
CEF6BFDD0919948A316156852563ACB0
1A49E62C1AED6642E40617218189CCB3
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn/OlFk7vLRQ6dBiNQkvjnhm4p
OYWo+GeAEmU4N1HPZj1dxv704hm80eYc7h12xc7oVcDLBdHByGAGBpQfpjgdPyoz
C/zSqcuU6iBrvzDTpyG1zhIG76KrcjdbX6PlKAPO9r/dCRmUijFhVoUlY6ywGknm
LBrtZkLkBhchgYnMswIDAQAB
-----END PUBLIC KEY-----

“pubin”告诉 rsa 这真的应该是公钥,不要抱怨它不是私钥。

现在我们获取 RSA 公钥,显示模数,并将其转换为普通的旧“公钥”(再次,我们必须告诉它输入是公钥):

>openssl rsa -in newclient_rsapublickey.pem -RSAPublicKey_in -modulus
Modulus=
A7FCE94593BBCB450E9D06235092F8E7
866E293985A8F867801265383751CF66
3D5DC6FEF4E219BCD1E61CEE1D76C5CE
E855C0CB05D1C1C8600606941FA6381D
3F2A330BFCD2A9CB94EA206BBF30D3A7
21B5CE1206EFA2AB72375B5FA3E52803
CEF6BFDD0919948A316156852563ACB0
1A49E62C1AED6642E40617218189CCB3
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn/OlFk7vLRQ6dBiNQkvjnhm4p
OYWo+GeAEmU4N1HPZj1dxv704hm80eYc7h12xc7oVcDLBdHByGAGBpQfpjgdPyoz
C/zSqcuU6iBrvzDTpyG1zhIG76KrcjdbX6PlKAPO9r/dCRmUijFhVoUlY6ywGknm
LBrtZkLkBhchgYnMswIDAQAB
-----END PUBLIC KEY-----

显示相同的模数和相同的“公钥”值。为了让事情变得更有趣(无论如何对我来说),当我们添加 RSAPublicKey_out 关键字时,我们会得到:

>openssl rsa -in newclient_rsapublickey.pem -RSAPublicKey_in -modulus -RSAPublicKey_out
Modulus=
A7FCE94593BBCB450E9D06235092F8E7
866E293985A8F867801265383751CF66
3D5DC6FEF4E219BCD1E61CEE1D76C5CE
E855C0CB05D1C1C8600606941FA6381D
3F2A330BFCD2A9CB94EA206BBF30D3A7
21B5CE1206EFA2AB72375B5FA3E52803
CEF6BFDD0919948A316156852563ACB0
1A49E62C1AED6642E40617218189CCB3
writing RSA key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKf86UWTu8tFDp0GI1CS+OeGbik5haj4Z4ASZTg3Uc9mPV3G/vTiGbzR
5hzuHXbFzuhVwMsF0cHIYAYGlB+mOB0/KjML/NKpy5TqIGu/MNOnIbXOEgbvoqty
N1tfo+UoA872v90JGZSKMWFWhSVjrLAaSeYsGu1mQuQGFyGBicyzAgMBAAE=
-----END RSA PUBLIC KEY-----

...当我们将普通的旧“公钥”转换为 RSA 公钥时:

>openssl rsa -in newclient_publickey.pem -pubin -RSAPublicKey_out
writing RSA key
-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBAKf86UWTu8tFDp0GI1CS+OeGbik5haj4Z4ASZTg3Uc9mPV3G/vTiGbzR
5hzuHXbFzuhVwMsF0cHIYAYGlB+mOB0/KjML/NKpy5TqIGu/MNOnIbXOEgbvoqty
N1tfo+UoA872v90JGZSKMWFWhSVjrLAaSeYsGu1mQuQGFyGBicyzAgMBAAE=
-----END RSA PUBLIC KEY-----

...无情地继续前进,虽然我们只是在几个命令之前执行了此操作,但为了说明这一点,我们将事情颠倒过来,所以变形是从 RSA 到普通的旧“公钥”:

>openssl rsa -in newclient_rsapublickey.pem -RSAPublicKey_in -pubout
writing RSA key
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn/OlFk7vLRQ6dBiNQkvjnhm4p
OYWo+GeAEmU4N1HPZj1dxv704hm80eYc7h12xc7oVcDLBdHByGAGBpQfpjgdPyoz
C/zSqcuU6iBrvzDTpyG1zhIG76KrcjdbX6PlKAPO9r/dCRmUijFhVoUlY6ywGknm
LBrtZkLkBhchgYnMswIDAQAB
-----END PUBLIC KEY-----

...这将我们带回到我们开始的地方。我们学到了什么?

总结:内部的键是相同的,只是看起来不同。较早的评论指出 RSA 密钥格式是在 PKCS#1 中定义的,而普通的旧“公钥”格式是在 PKCS#8 中定义的。但是,编辑一种形式并不会将其变成另一种形式。希望我现在已经战胜了这种区别。

如果还剩下一点生命的火花,让我们再鞭打一下,参考很久以前用 RSA 私钥生成的证书,检查它的公钥和模数:

>openssl x509 -in newclient_cert.pem -pubkey -noout -modulus
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCn/OlFk7vLRQ6dBiNQkvjnhm4p
OYWo+GeAEmU4N1HPZj1dxv704hm80eYc7h12xc7oVcDLBdHByGAGBpQfpjgdPyoz
C/zSqcuU6iBrvzDTpyG1zhIG76KrcjdbX6PlKAPO9r/dCRmUijFhVoUlY6ywGknm
LBrtZkLkBhchgYnMswIDAQAB
-----END PUBLIC KEY-----
Modulus=
A7FCE94593BBCB450E9D06235092F8E7
866E293985A8F867801265383751CF66
3D5DC6FEF4E219BCD1E61CEE1D76C5CE
E855C0CB05D1C1C8600606941FA6381D
3F2A330BFCD2A9CB94EA206BBF30D3A7
21B5CE1206EFA2AB72375B5FA3E52803
CEF6BFDD0919948A316156852563ACB0
1A49E62C1AED6642E40617218189CCB3

...他们从此过上了幸福的生活:证书具有与 RSA 公钥、RSA 私钥和普通旧“公钥”相同的模值。该证书包含与我们之前看到的相同的普通旧“公钥”值,尽管它是使用标记为 RSA 私钥的文件签名的。可以肯定地说有共识。

OpenSSL 星系的 X509 象限中没有“RSAPublicKey_out”等效关键字,因此我们不能尝试这样做,尽管模值被描述为“RSA 密钥模数”,我认为它与我们将要的一样接近得到。

我不知道使用 DSA 签名的证书会是什么样子。

我意识到这并不能回答最初的问题,但也许它提供了一些有用的背景。如果没有,我很抱歉。至少,不要做的事情和不要做的假设。

毫无疑问,人们已经注意到“编写 RSA 密钥”的重复有点令人讨厌,而实际上它并没有做任何这样的事情。我认为这意味着 rsa 模块将普通的旧公钥识别为真正的 RSA 密钥,这就是为什么它不断强调“RSA 密钥”(毕竟它是 rsa 模块)。如果我没记错的话,通用 EVP_PKEY 结构对所有键类型都有一个联合,每个键类型都有自己的一组特殊值(有用的命名为 g、w、q 和其他辅音)。

最后,我注意到有人抱怨编程和开发;现在,每个 OpenSSL 命令显然都有相应的代码,如果想探索当今 OpenSSL 编程的所有奇迹,命令行似乎是一个合理的起点。在这种特殊情况下(因为我目前正在使用最近的 cygwin),可以从查看 \openssl-1.0.2f\apps\rsa.c 和(假设对宏具有很高的容忍度)\openssl-1.0 开始。 2f\crypto\pem\pem_all.c

【讨论】:

以上是关于如何在两种公钥格式之间进行转换,一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY”的主要内容,如果未能解决你的问题,请参考以下文章

如何使用three.js在两种颜色之间进行补间?

常见的数字证书格式与格式转换

OpenSSL生成公钥私钥

与json交互

各种格式SSH 公钥和私钥之间的转换

将 NumPy 数组转换为 cufftComplex