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

我想使用RSA公钥encryption。 什么是存储或检索私钥和公钥的最佳方式? XML是一个好主意吗?

如何获得钥匙?

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

由于RSAParameters具有以下成员:D,DP,DQ,指数,InverseQ,模数,P,Q

哪一个是关键?

我所做的成功是将密钥存储为XML。 RSACryptoServiceProvider中有两个方法:ToXMLString和FromXMlString。 ToXMLString将返回一个包含公钥数据或公钥和私钥数据的XMLstring,具体取决于您如何设置其参数。 当提供一个只包含公钥数据或公钥和私钥数据的XMLstring时,FromXMLString方法将使用适当的密钥数据填充RSACryptoServiceProvider。

我想指出的东西作为回应评论ala询问是否:

公钥=模数+指数

这是完全正确的。 存储这个exponent + modulus数有几种方法。 标准的第一次尝试是RFC 3447 ( 公钥encryption标准(PKCS)#1:RSAencryption规范版本2.1 ),它定义了一个称为RSAPublicKey公钥结构:

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

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

  • 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 ( 安全shell(SSH)公钥文件格式 )。 它们包括algorithm标识符( ssh-rsa ),在指数和模数之前:

 string "ssh-rsa" mpint e mpint n 

他们不想使用DER ASN.1编码(因为它非常复杂),而是select了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 ( 互联网X.509公钥基础设施证书和CRLconfiguration文件 )。 他们采取了PKCS#1公钥格式:

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

并将其扩展为包含一个algorithm标识符前缀(如果您想使用RSA以外的公钥encryptionalgorithm):

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

RSA的“algorithm标识符”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编码为hex的非常复杂的方法,但是最终的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的头来包装它,但是没有“RSA”(因为它可能不是RSA):

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

这就是您创buildX.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公钥易于使用的RSAKeyValue

  • 指数0x 010001 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> 

简单得多。 不利的一面是,它不包装,复制,粘贴,就像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编码的hex数据(可以从Translator, Binary
  • Microsoft ASN.1文档 :描述用于ASN.1结构的专有编码规则(DER)(您不会在其他地方find更好的文档集;我认为微软不仅仅是真实的文档)

使用现有的标准格式,如PEM。 你的encryption库应该提供从PEM格式的文​​件加载和保存密钥的function。

指数和模数是公钥。 D和Modulus是私钥。 其他值允许更快地计算私钥的持有者。

公钥由Modulus和Exponent标识。 私钥由其他成员识别。

XML是一个好主意吗?

通常,私钥存储在HSM /智能卡中。 这提供了很好的安全性。