如何在两种公钥格式之间进行转换?一种格式是:
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
另一种格式是:
-----BEGIN RSA PUBLIC KEY-----
...
-----END RSA PUBLIC KEY-----
例如,我生成id_rsa/id_rsa。使用ssh-keygen命令发布对我使用以下命令从id_rsa中计算出公钥:
openssl rsa -in id_rsa -pubout -out pub2
然后我再次从id_rsa中计算公钥。使用:
发布ssh-keygen -f id_rsa.pub -e -m pem > pub1
内容为pub1 is:
-----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包含相同的公钥信息,但它们的格式不同,我想知道我如何在两种格式之间转换?谁能给我简单介绍一下这两种格式?
我想帮助解释一下这里发生了什么。
RSA公钥由两个数字组成:
- 模数(例如2,048位数)
- 指数(通常为65,537)
以您的RSA公钥为例,这两个数字是:
- 模量:297056429939040947991047334197581225628107021573849359042679698093131908015712695688944173317630555849768647118986535684992447654339728777985990170679511111819558063246667855023730127805401069042322764200545883378826983730553730138478384327116513143842816383440639376515039682874046227217032079079790098143158087443017552531393264852461292775129262080851633535934010704122673年,027067442627059982393297716922243940155855127430302323883824137412883916794359982603439112095116831297809626059569444750808699678211904501083183234323797142810155862553705570600021649944369726123996534870137000784980673984909570977377882585701 指数
- : 65537
那么问题就变成了我们如何在计算机中存储这些数字。首先将两者转换为十六进制:
- 模量:EB506399F5C612F5A67A09C1192B92FAB53DB28520D859CE0EF6B7D83D40AA1C1DCE2C0720D15A0F531595CAD81BA5D129F91CC6769719F1435872C4BCD0521150A0263B470066489B918BFCA03CE8A0E9FC2C0314C4B096EA30717C03C28CA29E678E63D78ACA1E9A63BDB1261EE7A0B041AB53746D68B57B68BEF37B71382838C95DA8557841A3CA58109F0B4F77A5E929B1A25DC2D6814C55DC0F81CD2F4E5DB95EE70C706FC02C4FCA358EA9A82D8043A47611195580F89458E3DAB5592DEFE06CDE1E516A6C61ED78C13977AE9660A9192CA75CD72967FD3AFAFA1F1A2FF6325A5064D847028F1E6B2329E8572F36E708A549DDA355FC74A32FDD8DBA65 指数
- : 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
之后,出现了其他形式的公钥加密:
- diffie - hellman <
- Ellicptic曲线/gh>
当需要创建一个标准来表示的参数时,加密算法,人们采用了很多RSA最初定义的相同思想:
- 使用ASN.1二进制编码
- base64它
- 用五个连字符 括起来
- 和
BEGIN PUBLIC KEY
而不是使用:
-----BEGIN RSA PUBLIC KEY-----
-----BEGIN DH PUBLIC KEY-----
-----BEGIN EC PUBLIC KEY-----
他们决定将对象标识符(OID)包含在后面的内容中。对于RSA公钥,即:
- RSA PKCS # 1:
1.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.509SubjectPublicKeyInfo/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个字节是"new"添加的内容:
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字节变成了4个字符:
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
格式。
我发现这个网站是一个很好的技术解释不同的格式:https://polarssl.org/kb/cryptography/asn1-key-structures-in-der-and-pem
BEGIN RSA PUBLIC KEY"是pkcs# 1,它只能包含RSA密钥。
BEGIN PUBLIC KEY"是一个SPKI(主题公钥信息)密钥(X.509的一部分),它可以包含多种格式。
如果你只是想用命令行转换它们,"openssl rsa"
将SPKI转换为pkcs# 1:
openssl rsa -pubin -in <filename> -RSAPublicKey_out
将pkcs# 1转换为SPKI:
openssl rsa -RSAPublicKey_in -in <filename> -pubout
使用phpseclib,一个纯PHP RSA实现…
<?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);
base64编码的内容看起来是匹配的,即使标头显示BEGIN PUBLIC KEY而不是BEGIN RSA PUBLIC KEY。所以也许只是使用str_replace来解决这个问题,你应该很好!
pub1和pub2之间的唯一区别,除了页眉/页脚之外,是pub2:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
中的这个附加字符串。如果你把它去掉,Base 64和pub1中的Base 64是一样的。
根据这个答案,额外的字符串对应于算法标识符。
转换为第三公钥样式(OpenSSH公钥格式):
输入文件:C:mc_pubkey.txt
:(inSSH2公钥格式)
---- BEGIN SSH2 PUBLIC KEY ----
Comment: "imported-openssh-key"
AAAAB3NzaC1yc2EAAAADAQABAAABAQCb4oUsXZ51L9DmH3UqSnwOAUr9w6AOZa8b
YH8qsJAhypAjH9YvQteVXXQEY0ybaVE1cmpIKEyC2jmC/jOJ4b7bivlo2hgnLOrj
3FPkDWO2yNNio9RnPXREBx7+iIi9pcaozUmiPMoPxaEyfpGQAvfdFzt+n6+o/hoO
72Zv5RSo0rGr76sLUjx9Mi5TnuI2rT4s9FGMZ9xkgUu3z11UcDhSXqkLEgEEDKBq
bft3VuiQm6Blggzk9tk5L1LAdKM7udhby9dOwXCYPnCKTymYTqi/2FTwKZDj5TJH
V8r6c2Sz/qEdgMkw7RD3ice9m9GYHi2Burgyvjw+Sla+yu0n9sBh
---- END SSH2 PUBLIC KEY ----
将其转换为OpenSSH公钥格式,使用ssh-keygen.exe
实用程序。它可能已经在您的计算机上了,因为它是与Git一起打包的。在Powershell中:
> cd C:Program FilesGitusrbin
> .ssh-keygen.exe -i -f "C:mc_pubkey.txt"
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCb4oUsXZ51L9DmH3UqSnwOAUr9w6AOZa8bYH8qsJAhypAjH9YvQteVXXQEY0ybaVE1cmpIKEyC2jmC/jOJ4b7bivlo2hgnLOrj3FPkDWO2yNNio9RnPXREBx7+iIi9pcaozUmiPMoPxaEyfpGQAvfdFzt+n6+o/hoO72Zv5RSo0rGr76sLUjx9Mi5TnuI2rT4s9FGMZ9xkgUu3z11UcDhSXqkLEgEEDKBqbft3VuiQm6Blggzk9tk5L1LAdKM7udhby9dOwXCYPnCKTymYTqi/2FTwKZDj5TJHV8r6c2Sz/qEdgMkw7RD3ice9m9GYHi2Burgyvjw+Sla+yu0n9sBh
这就是你想要的输出!复制粘贴并保存到文件中,就完成了。