簡體   English   中英

如何存儲/檢索 RSA 公鑰/私鑰

[英]How to store/retrieve RSA public/private key

我想使用 RSA 公鑰加密。 存儲或檢索私鑰和公鑰的最佳方法是什么? XML 在這里是個好主意嗎?

鑰匙怎么獲得?

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

因為 RSAParameters 有以下成員:D、DP、DQ、Exponent、InverseQ、Modulus、P、Q

哪個是關鍵?

我想指出一些事情作為對ala評論的回應,詢問是否:

公鑰=模數+指數

這是完全正確的。 有幾種方法可以存儲這個exponent + modulus 標准的第一次嘗試是在RFC 3447公鑰加密標准(PKCS)#1:RSA加密規范版本2.1 )中,它定義了一個名為RSAPublicKey公鑰的結構:

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

同樣的RFC繼續聲明您應該使用ASN.1編碼DER flavor來存儲公鑰。 我有一個示例公鑰:

  • 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 2459Internet 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中看到它們如何將舊的RSAPublicKeyOBJECT_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 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編碼的十六進制數據(來自Translator, Binary
  • Microsoft ASN.1文檔 :描述用於ASN.1結構的可分辨編碼規則(DER)(在其他任何地方都找不到更好的文檔集;我認為Microsoft不僅僅是真正的文檔)

我成功完成的是將密鑰存儲為XML。 RSACryptoServiceProvider中有兩種方法:ToXmlString和FromXmlString。 ToXmlString將返回一個XML字符串,該字符串僅包含公鑰數據或公鑰和私鑰數據,具體取決於您設置其參數的方式。 當提供包含公鑰數據或公鑰和私鑰數據的XML字符串時,FromXmlString方法將使用適當的密鑰數據填充RSACryptoServiceProvider。

使用現有的標准格式,如PEM。 您的加密庫應該提供從PEM格式的文​​件加載和保存密鑰的功能。

指數和模數是公鑰。 D和Modulus是私鑰。 其他值允許更快地計算私鑰的持有者。

公鑰由模數和指數標識。 私鑰由其他成員標識。

我想@Ian Boyd 的回答不准確,格式應該是 SSH2,而不是 OpenSSH,因為為 SSH2 定義的 RFC4716,OpenSSH 格式是專有的:

注意:OpenSSH 使用四個帶空格的破折號 (---- ) 而不是五個破折號和沒有空格 (----- )。

XML在這里是個好主意嗎?

通常私鑰存儲在HSM /智能卡中。 這提供了良好的安全性。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM