当前位置:  开发笔记 > 编程语言 > 正文

如何存储/检索RSA公钥/私钥

如何解决《如何存储/检索RSA公钥/私钥》经验,为你挑选了2个好方法。

我想使用RSA公钥加密.存储或检索私钥和公钥的最佳方法是什么?XML在这里是个好主意吗?

如何获得钥匙?

RSAParameters privateKey = RSA.ExportParameters(true);
RSAParameters publicKey = RSA.ExportParameters(false);

因为RSAParameters具有以下成员:D,DP,DQ,Exponent,InverseQ,Modulus,P,Q

哪一个是关键?



1> Ian Boyd..:

我想指出一些事情作为对ala评论的回应,询问是否:

公钥=模数+指数

这是完全正确的.有几种方法可以存储这个exponent+ modulus.标准的第一次尝试是在RFC 3447 (公钥加密标准(PKCS)#1:RSA加密规范版本2.1)中,它定义了被叫公钥的结构RSAPublicKey:

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

同样的RFC继续声明您应该使用DER flavor ASN.1编码来存储公钥.我有一个示例公钥:

publicExponent:65537 (所有RSA公钥都使用65537作为其指数是惯例)

模数:0xDC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 8209 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 995D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55

此公钥的DER ASN.1编码为:

30 81 89          ;SEQUENCE (0x89 bytes = 137 bytes)
|  02 81 81       ;INTEGER (0x81 bytes = 129 bytes)
|  |  00          ;leading zero of INTEGER
|  |  DC 67 FA
|  |  F4 9E F2 72 1D 45 2C B4  80 79 06 A0 94 27 50 82
|  |  09 DD 67 CE 57 B8 6C 4A  4F 40 9F D2 D1 69 FB 99
|  |  5D 85 0C 07 A1 F9 47 1B  56 16 6E F6 7F B9 CF 2A
|  |  58 36 37 99 29 AA 4F A8  12 E8 4F C7 82 2B 9D 72
|  |  2A 9C DE 6F C2 EE 12 6D  CF F0 F2 B8 C4 DD 7C 5C
|  |  1A C8 17 51 A9 AC DF 08  22 04 9D 2B D7 F9 4B 09
|  |  DE 9A EB 5C 51 1A D8 F8  F9 56 9E F8 FB 37 9B 3F
|  |  D3 74 65 24 0D FF 34 75  57 A4 F5 BF 55
|  02 03          ;INTEGER (0x03 = 3 bytes)
|  |  01 00 01    ;hex for 65537. see it?

如果您将以上整个DER ASN.1编码modulus+ exponent:

30 81 89 02 81 81 00 DC 67 FA F4 9E F2 72 1D 45 2C B4 80 79 06 A0 94 27 50 82 09 DD 67 CE 57 B8 6C 4A 4F 40 9F D2 D1 69 FB 99 5D 85 0C 07 A1 F9 47 1B 56 16 6E F6 7F B9 CF 2A 58 36 37 99 29 AA 4F A8 12 E8 4F C7 82 2B 9D 72 2A 9C DE 6F C2 EE 12 6D CF F0 F2 B8 C4 DD 7C 5C 1A C8 17 51 A9 AC DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F8 F9 56 9E F8 FB 37 9B 3F D3 74 65 24 0D FF 34 75 57 A4 F5 BF 55 02 03 01 00 01

PEM编码它(即base64):

MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY
UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE
3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV
ek9b9VAgMBAAE=

将base64编码数据包装在以下内容中是一种惯例:

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY
UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE
3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV
ek9b9VAgMBAAE=
-----END RSA PUBLIC KEY-----

这就是你如何得到一个PEM DER ASN.1 PKCS#1 RSA公钥.


下一个标准是RFC 4716(安全外壳(SSH)公钥文件格式).它们包括一个算法标识符(ssh-rsa),在指数和模数之前:

string    "ssh-rsa"
mpint     e
mpint     n

他们不想使用DER ASN.1编码(因为它非常复杂),而是选择了4字节长度的前缀:

00000007                 ;7 byte algorithm identifier
73 73 68 2d 72 73 61     ;"ssh-rsa"
00000003                 ;3 byte exponent
01 00 01                 ;hex for 65,537 
00000080                 ;128 byte modulus
DC 67 FA F4 9E F2 72 1D  45 2C B4 80 79 06 A0 94 
27 50 82 09 DD 67 CE 57  B8 6C 4A 4F 40 9F D2 D1 
69 FB 99 5D 85 0C 07 A1  F9 47 1B 56 16 6E F6 7F 
B9 CF 2A 58 36 37 99 29  AA 4F A8 12 E8 4F C7 82 
2B 9D 72 2A 9C DE 6F C2  EE 12 6D CF F0 F2 B8 C4 
DD 7C 5C 1A C8 17 51 A9  AC DF 08 22 04 9D 2B D7 
F9 4B 09 DE 9A EB 5C 51  1A D8 F8 F9 56 9E F8 FB 
37 9B 3F D3 74 65 24 0D  FF 34 75 57 A4 F5 BF 55

取整个上面的字节序列并对其进行base-64编码:

AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs
Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4S
bc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80
dVek9b9V

并将其包装在OpenSSH标题和预告片中:

---- BEGIN SSH2 PUBLIC KEY ----
AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs
Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4S
bc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80
dVek9b9V
---- END SSH2 PUBLIC KEY ----

注意:OpenSSH使用带有空格(----)的四个破折号而不是五个破折号而没有空格(-----).


下一个标准是RFC 2459(Internet X.509公钥基础结构证书和CRL配置文件).他们采用了PKCS#1公钥格式:

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

并扩展到包括算法标识符前缀(如果你想使用公钥加密算法比RSA):

SubjectPublicKeyInfo  ::=  SEQUENCE  {
    algorithm            AlgorithmIdentifier,
    subjectPublicKey     RSAPublicKey }

RSA 的"算法标识符"1.2.840.113549.1.1.1来自:

1 - ISO分配的OID

1.2 - ISO成员机构

1.2.840 - 美国

1.2.840.113549 - RSADSI

1.2.840.113549.1 - PKCS

1.2.840.113549.1.1 - PKCS-1

X.509是一个非常糟糕的标准,它定义了一种非常复杂的编码OID为十六进制的方式,但最后X.509 SubjectPublicKeyInfoRSA公钥的DER ASN.1编码是:

30 81 9F            ;SEQUENCE (0x9f bytes = 159 bytes)
|  30 0D            ;SEQUENCE (0x0d bytes = 13 bytes)
|  |  06 09         ;OBJECT_IDENTIFIER (0x09 = 9 bytes)
|  |  2A 86 48 86   ;Hex encoding of 1.2.840.113549.1.1
|  |  F7 0D 01 01 01
|  |  05 00         ;NULL (0 bytes)
|  03 81 8D 00      ;BIT STRING (0x8d bytes = 141 bytes)
|  |  30 81 89          ;SEQUENCE (0x89 bytes = 137 bytes)
|  |  |  02 81 81       ;INTEGER (0x81 bytes = 129 bytes)
|  |  |  00          ;leading zero of INTEGER
|  |  |  DC 67 FA
|  |  |  F4 9E F2 72 1D 45 2C B4  80 79 06 A0 94 27 50 82
|  |  |  09 DD 67 CE 57 B8 6C 4A  4F 40 9F D2 D1 69 FB 99
|  |  |  5D 85 0C 07 A1 F9 47 1B  56 16 6E F6 7F B9 CF 2A
|  |  |  58 36 37 99 29 AA 4F A8  12 E8 4F C7 82 2B 9D 72
|  |  |  2A 9C DE 6F C2 EE 12 6D  CF F0 F2 B8 C4 DD 7C 5C
|  |  |  1A C8 17 51 A9 AC DF 08  22 04 9D 2B D7 F9 4B 09
|  |  |  DE 9A EB 5C 51 1A D8 F8  F9 56 9E F8 FB 37 9B 3F
|  |  |  D3 74 65 24 0D FF 34 75  57 A4 F5 BF 55
|  |  02 03          ;INTEGER (0x03 = 3 bytes)
|  |  |  01 00 01    ;hex for 65537. see it?

你可以在解码的ASN.1中看到他们如何只用旧的前缀RSAPublicKey加上OBJECT_IDENTIFIER.

取以上字节和PEM(即base-64)对它们进行编码:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC
Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y
Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/
03RlJA3/NHVXpPW/VQIDAQAB

然后标准用一个类似于RSA PKCS#1的标题包装它,但没有"RSA"(因为它可能是RSA以外的东西):

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcZ/r0nvJyHUUstIB5BqCUJ1CC
Cd1nzle4bEpPQJ/S0Wn7mV2FDAeh+UcbVhZu9n+5zypYNjeZKapPqBLoT8eCK51y
Kpzeb8LuEm3P8PK4xN18XBrIF1GprN8IIgSdK9f5SwnemutcURrY+PlWnvj7N5s/
03RlJA3/NHVXpPW/VQIDAQAB
-----END PUBLIC KEY-----

这就是你如何发明X.509 SubjectPublicKeyInfo/OpenSSL PEM公钥格式.


这并不会停止RSA公钥的标准格式列表.接下来是OpenSSH使用的专有公钥格式:

SSH-RSA AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn + vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk + oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4 + VAE + Ps3mz/TdGUkDf80dVek9b9V

这实际上是上面的SSH公钥格式,但前缀是ssh-rsa,而不是包装在---- BEGIN SSH2 PUBLIC KEY ----/中---- END SSH2 PUBLIC KEY ----.


这就是XML RSAKeyValue公钥的易用性所在:

指数:0x 010001base64编码为AQAB

模数:0x 00 dc 67 fa f4 9e f2 72 1d 45 2c b4 80 79 06 a0 94 27 50 82 09 dd 67 ce 57 b8 6c 4a 4f 40 9f d2 d1 69 fb 99 5d 85 0c 07 a1 f9 47 1b 56 16 6e f6 7f b9 cf 2a 58 36 37 99 29 aa 4f a8 12 e8 4f c7 82 2b 9d 72 2a 9c de 6f c2 ee 12 6d cf f0 f2 b8 c4 dd 7c 5c 1a c8 17 51 a9 ac df 08 22 04 9d 2b d7 f9 4b 09 de 9a eb 5c 51 1a d8 f8 f9 56 9e f8 fb 37 9b 3f d3 74 65 24 0d ff 34 75 57 a4 f5 bf 55base64编码是ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V.

这意味着XML是:


   ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V
   AQAB

更简单.缺点是它不会像包装,复制,粘贴一样好(即Xml不像用户友好):

-----BEGIN RSA PUBLIC KEY-----
MIGJAoGBANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXY
UMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE
3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dV
ek9b9VAgMBAAE=
-----END RSA PUBLIC KEY-----

但它创造了一个很好的中立存储格式.

也可以看看

译者,二进制:非常适合解码和编码base64数据

ASN.1 JavaScript解码器:非常适合解码ASN.1编码的十六进制数据(您获得的数据)Translator, Binary

Microsoft ASN.1文档:描述用于ASN.1结构的可分辨编码规则(DER)(在其他任何地方都找不到更好的文档集;我认为Microsoft不仅仅是真正的文档)


很棒的答案!不要精确回答相关问题,而是广泛而可靠的RSA密钥信息来源.令人印象深刻的工作:o
很好地解释了格式之间的关系,但只有一点:**PEM使用5个破折号**不等于.SSH2的确会改变为4和1个空格,但不会更改字符.
我可以问一个问题吗?为什么模数由如此多的字符组成?它是以某种特定方式编码的大数字吗?谢谢!

2> Joe Kuemerle..:

我成功完成的是将密钥存储为XML.RSACryptoServiceProvider中有两种方法:ToXmlString和FromXmlString.ToXmlString将返回一个XML字符串,该字符串仅包含公钥数据或公钥和私钥数据,具体取决于您设置其参数的方式.当提供包含公钥数据或公钥和私钥数据的XML字符串时,FromXmlString方法将使用适当的密钥数据填充RSACryptoServiceProvider.


@LOSTCODER XML的价值在于至少有7种其他标准可以存储RSA密钥材料.至少使用XML,您可以将值((模数`,`指数`为公钥,'D`,'P`,`Q`,`DP`,`DQ`,`InverseQ`)简单地视为base64编码字节数据.从那里你可以将它转换回PKCS#1,PKCS#7,PKCS#8,PFX,证书,OpenSSH,OpenSSL等.简而言之:XML是可移植的,而其他一切都是复杂的专有(例如ASN.1 DER, [甚至没有明确的标准](http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt))
推荐阅读
放ch养奶牛
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有