Cómo almacenar / recuperar la clave pública / privada de RSA

Quiero usar el cifrado de clave pública RSA. ¿Cuál es la mejor manera de almacenar o recuperar claves privadas y públicas? ¿Es XML una buena idea aquí?

¿Cómo obtener las llaves?

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

Porque los RSAParameters tienen los siguientes miembros: D, DP, DQ, Exponent, InverseQ, Modulus, P, Q

¿Cuál es la clave?

Lo que he hecho con éxito es almacenar las claves como XML. Hay dos métodos en RSACryptoServiceProvider: ToXmlString y FromXmlString. ToXmlString devolverá una cadena XML que contiene solo los datos de la clave pública o los datos de la clave pública y privada, según cómo establezca su parámetro. El método FromXmlString llenará RSACryptoServiceProvider con los datos clave apropiados cuando se proporcione una cadena XML que contenga solo los datos de clave pública o los datos de clave pública y privada.

Quería señalar algo como respuesta a un comentario de ala preguntando si:

Clave pública = módulo + exponente

Eso es exactamente correcto. Hay algunas formas de almacenar este exponent + modulus . El primer bash en un estándar fue en RFC 3447 ( Estándares de criptografía de clave pública (PKCS) n. ° 1: Especificaciones de criptografía RSA versión 2.1 ), que define una estructura para una clave pública de RSAPublicKey llamada:

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

El mismo RFC continúa para declarar que debe usar el sabor DER de la encoding ASN.1 para almacenar la clave pública. tengo una clave pública de muestra:

  • publicExponent : 65537 (es una convención que todas las claves públicas de RSA usan 65537 como su exponente)
  • módulo : 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

La encoding DER ASN.1 de esta clave pública es:

 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? 

Si tomas todo el modulus codificado + exponent DER ASN.1 anterior:

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

y tu PEM lo codifica (es decir, base64):

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

Es una convención para envolver esos datos codificados en base64 en:

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

Y así es como se obtiene una clave pública RSA PEM DER ASN.1 PKCS # 1 .


El siguiente estándar fue RFC 4716 (el formato de archivo de clave pública Secure Shell (SSH) ). Incluyeron un identificador de algoritmo ( ssh-rsa ), antes del exponente y el módulo:

 string "ssh-rsa" mpint e mpint n 

No querían usar la encoding DER ASN.1 (ya que es tremendamente complejo), y optaron por el prefijo de 4 bytes de longitud :

 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 

Tome toda la secuencia de bytes anterior y base-64 la codifique:

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

Y envuélvalo en el encabezado y el avance de OpenSSH:

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

Nota : OpenSSH usa cuatro guiones con un espacio ( ---- ) en lugar de cinco guiones y ningún espacio ( ----- ).


El siguiente estándar fue RFC 2459 ( Internet X.509 Public Key Infrastructure Certificate y CRL Profile ). Tomaron el formato de clave pública PKCS # 1:

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

y lo extendió para incluir un prefijo de identificador de algoritmo (en caso de que desee utilizar un algoritmo de cifrado de clave pública distinto de RSA):

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

El “Identificador de Algoritmo” para RSA es 1.2.840.113549.1.1.1 , que proviene de:

  • 1 – OID asignados ISO
    • 1.2 – Cuerpo miembro de ISO
      • 1.2.840 – Estados Unidos
        • 1.2.840.113549 – RSADSI
          • 1.2.840.113549.1 – PKCS
            • 1.2.840.113549.1.1 – PKCS-1

El X.509 es un estándar horrible, que define una forma terriblemente complicada de codificar un OID en hexadecimal, pero al final la encoding DER ASN.1 de una clave pública SubjectPublicKeyInfo RSA es:

 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? 

Puede ver en el ASN.1 decodificado cómo ellos simplemente prefijaron la antigua RSAPublicKey con un OBJECT_IDENTIFIER .

Tomando los bytes anteriores y PEM (es decir, base-64) codificándolos:

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

El estándar es entonces envolver esto con un encabezado similar a RSA PKCS # 1, pero sin el “RSA” (ya que podría ser algo diferente a RSA):

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

Y así es como inventa un formato de clave pública X.509 SubjectPublicKeyInfo / OpenSSL PEM .


Eso no detiene la lista de formatos estándar para una clave pública de RSA. El siguiente es el formato de clave pública patentado utilizado por OpenSSH:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgNxn + vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hs Sk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk + oEuhPx4IrnXIqnN5vwu4Sbc / w8rjE3XxcGsgXUams3wgiBJ0r1 / lLCd6a61xRGtj4 + + Vae Ps3mz / TdGUkDf80dVek9b9V

Que en realidad es el formato de clave pública SSH anterior, pero con el prefijo ssh-rsa , en lugar de estar en ---- BEGIN SSH2 PUBLIC KEY ---- / ---- END SSH2 PUBLIC KEY ---- .


Aquí es donde entra en RSAKeyValue la facilidad de la clave pública XML RSAKeyValue :

  • Exponente : 0x 010001 base64 codificado es AQAB
  • Módulo : 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 codificado es ANxn+vSe8nIdRSy0gHkGoJQnUIIJ3WfOV7hsSk9An9LRafuZXYUMB6H5RxtWFm72f7nPKlg2N5kpqk+oEuhPx4IrnXIqnN5vwu4Sbc/w8rjE3XxcGsgXUams3wgiBJ0r1/lLCd6a61xRGtj4+Vae+Ps3mz/TdGUkDf80dVek9b9V .

Esto significa que el XML es:

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

Mucho más simple Un inconveniente es que no se ajusta, copia, pega, tan bien como (es decir, Xml no es tan fácil de usar como):

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

Pero hace un excelente formato de almacenamiento neutral.

Ver también

  • Traductor, binario : excelente para decodificar y codificar datos base64
  • Decodificador de JavaScript ASN.1 : ideal para decodificar datos hexadecimales codificados en ASN.1 (que se obtienen de Translator, Binary
  • Documentación de Microsoft ASN.1 : Describe las reglas de encoding distinguida (DER) utilizadas para las estructuras de ASN.1 (no encontrará un mejor conjunto de documentación en ningún otro lado; yo diría que Microsoft no es solo documentación real)

Use un formato estándar existente, como PEM. Su biblioteca de cifrado debe proporcionar funciones para cargar y guardar claves de archivos en formato PEM.

El exponente y el módulo son la clave pública. D y Modulus son la clave privada. Los otros valores permiten un cálculo más rápido para el titular de la clave privada.

La clave pública se identifica por Módulo y Exponente. La clave privada es identificada por los otros miembros.

¿Es XML una buena idea aquí?

Normalmente, las claves privadas se almacenan en HSM / tarjeta inteligente. Esto proporciona una buena seguridad.