RSACryptoServiceProvider , como La mayoría de las clases de sistemas en .NET, es una envoltura delgada alrededor de la implementación anterior de Win32 (una API que fue diseñada para ser utilizada con C o C ++, o incluso con Pascal, si realmente profundizamos). Consulte CryptAcquireContext () . En la terminología .NET, esto se llama "código no administrado".
La generación de un par de claves RSA implica producir nuevos números primos aleatorios. El conocimiento de estos números primos es la clave privada, por lo que esperamos que la implementación de Microsoft simplemente no use una lista fija de números primos generados previamente. Conceptualmente, esta generación es simple: produzca secuencias de bits aleatorios del tamaño correcto y repita hasta que encuentre uno que sea primordial.
En más detalles, si desea una clave RSA de 2048 bits, necesitará dos números primos de 1024 bits cuyo producto sea un entero de 2048 bits. Esto va de esa manera:
-
Genere una secuencia de 1024 bits aleatorios, de modo que los dos primeros bits y el último sean iguales a 1; los 1021 otros bits se obtienen de una fuente aleatoria fuerte (en Win32, esto es CryptGenRandom () - RNGCryptoServiceProvider
es el contenedor .NET).
-
Interpreta los 1024 bits como un entero grande p . Dado que establecimos los dos primeros bits en 1, y hay 1024 bits, entonces el número entero es mayor que 3 × 2 1022 y menor que 4 × 2 1022 ; como el último bit también es 1, el entero es impar.
-
Verifique que p -1 no sea un múltiplo del exponente público RSA elegido. El exponente tradicional es 65537. Existe una probabilidad 1/65537 de que p -1 es un múltiplo de 65537; si eso es nuevo, vuelva al paso 1 para generar otro candidato.
-
Pruebe el entero p para determinar la primalidad. Hay varios métodos para eso; por lo general, se utiliza la prueba de primalidad de Miller-Rabin . Si no se encuentra que p sea primo, vuelva al paso 1 para generar otro primo. Para un p de 1024 bits que nos encargamos de hacer impares, puede esperar probar un promedio de unos 500 candidatos antes de encontrar un primo.
-
Una vez que hayas generado un primo aleatorio p , hazlo nuevamente para obtener otro, que llamaremos q .
-
El módulo será n = pq . El exponente público es el e elegido (65537 en el ejemplo anterior). El exponente privado d y los otros componentes de la clave privada RSA se calculan algebraicamente desde p , q y e . Gracias a la forma en que se generaron p y q (dos bits superiores iguales a 1), se garantiza que n tendrá un tamaño de 2048 bits, no 2047.
La API completa es apenas utilizable. El concepto de la "clave predeterminada" es aberrante; No puede confiar decentemente en él en ningún protocolo, ya que no controla ni su almacenamiento ni su ciclo de vida. Además, esa clave predeterminada tendrá una longitud de 1024 bits, lo que es un poco demasiado corto para la tecnología actual. Si desea obtener y utilizar una clave RSA, debe solicitar su generación explícitamente y, por supuesto, no registrarla como un "valor predeterminado" que cualquier otra aplicación puede usar o posible modificar, exportar, publicar o lo que sea.
También está mal subespecificado. CryptAcquireContext () acepta múltiples opciones que afectan la forma en que se genera y almacena la clave, si la hubiera; La documentación de RSACryptoServiceProvider no indica qué opciones se utilizan. Si desea saber lo que realmente sucede bajo el capó, debe profundizar en el código fuente .
La conclusión es que el constructor RSACryptoServiceProvider generará nuevos primos, para un módulo RSA de 1024 bits (por lo tanto, primos de 512 bits), pero intentará mantener una "clave predeterminada" "para que lo haga solo una vez, incluso si lo llama repetidamente. Tenga en cuenta que producir una nueva clave RSA de 1024 bits toma solo una fracción de segundo con una PC moderna.