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

5jvtdoz2  于 2023-03-31  发布在  .NET
关注(0)|答案(6)|浏览(191)

我想使用RSA公钥加密。存储或检索私钥和公钥的最佳方法是什么?XML是一个好主意吗?
怎么拿到钥匙?

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

因为RSA参数具有以下成员:D、DP、DQ、Exponent、InverseQ、Modulus、P、Q
哪个是钥匙?

dgjrabp2

dgjrabp21#

我想指出一些东西作为对阿拉评论的回应,询问是否:
公钥=模数+指数
这是完全正确的。有几种存储exponent + modulus的方法。第一次尝试标准是在RFC 3447(* 公钥密码标准(PKCS)#1:RSA Cryptography Specifications Version 2.1*),它定义了一个名为**RSAPublicKey**的公钥结构:

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

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

*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 5836 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交流DF 08 22 04 9D 2B D7 F9 4B 09 DE 9A EB 5C 51 1A D8 F9 56 9E F8 FB 37 9B 3F D3 7465 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编码的数据 Package 在:

-----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(* 安全 shell (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

并将其 Package 在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 SubjectPublicKeyInfo RSA公钥的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中看到他们如何用OBJECT_IDENTIFIER前缀旧的RSAPublicKey
取上述字节并对它们进行PEM(即base-64)编码:

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

然后,标准是用类似于RSA PKCS#1的头来 Package 它,但没有“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使用的专有公钥格式:
单克隆抗体AAAAB 3 NzaC 1 yc 2 EAAAADAQABAAAAgNxn + vSe 8 nIdRSy 0 gHkGoJQnUIIJ 3 WfOV 7 hs Sk 9A 9 LRafuZXYUMB 6 H5 RxtWFm 72 f7 nPKlg 2N 5 kpqk + oEuhPx 4 IrnXiqnN 5vwu 4Sbc/w8 rjE 3XcGsgXUams 3 wgiBJ 0 r1/lLCd 6a 61 xRGtj 4 +Vae+ Ps3 mz/TdGUkDf 80 dVek 9 b 9V
它实际上是上面的SSH公钥格式,但前缀是ssh-rsa,而不是 Package 在---- BEGIN SSH2 PUBLIC KEY ----/---- END SSH2 PUBLIC KEY ----中。
这就是XML RSAKeyValue public key的易用性所在:

*指数:base64编码为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 55 base64编码为ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V

这意味着XML是:

<RSAKeyValue>
   <Modulus>ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V</Modulus>
   <Exponent>AQAB</Exponent>
</RSAKeyValue>

简单得多。缺点是它不像 Package ,复制,粘贴一样好(即Xml不像用户友好):

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

但它使一个伟大的中性存储格式。

参见

  • Translator, Binary:非常适合解码和编码base64数据
  • ASN.1 JavaScript decoder:非常适合解码ASN.1编码的十六进制数据(从Translator, Binary获得
  • Microsoft ASN.1 Documentation:描述用于ASN.1结构的可分辨编码规则(Distinguished Encoding Rules,DER)(您在其他地方找不到更好的文档集;我认为微软的不仅仅是真实的文档)
lmvvr0a8

lmvvr0a82#

我成功地将密钥存储为XML。在RSACryptoServiceProvider中有两个方法:ToXmlString和FromXmlString。ToXmlString将返回仅包含公钥数据或同时包含公钥和私钥数据的XML字符串,具体取决于您如何设置其参数。当提供仅包含公钥数据或同时包含公钥和私钥数据的XML字符串时,FromXmlString方法将使用相应的密钥数据填充RSACryptoServiceProvider。

ctehm74n

ctehm74n3#

使用现有的标准格式,如PEM。您的加密库应提供从PEM格式的文件中加载和保存密钥的函数。
指数和模数是公钥。D和模数是私钥。其他值允许私钥保持器更快地计算。

1cosmwyk

1cosmwyk4#

公钥由模和指数标识,私钥由其他成员标识。

r8xiu3jd

r8xiu3jd5#

我想@Ian Boyd的回答并不准确,格式应该是SSH 2,而不是OpenSSH,因为为SSH 2定义的RFC 4716、OpenSSH格式是专有的:
注意:OpenSSH使用四个带空格的破折号(----),而不是五个不带空格的破折号(-----)。

pod7payv

pod7payv6#

XML是一个好主意吗?
通常私钥存储在HSM/智能卡中。这提供了良好的安全性。

相关问题