c# - bouncy - RSA Encrypt/Decrypt Problem en.NET
rsacryptoserviceprovider c# (5)
Tengo un problema con el cifrado y descifrado de C # mediante RSA. He desarrollado un servicio web al que se enviará información y transacciones financieras confidenciales. Lo que me gustaría poder hacer es en el lado del cliente, Cifrar ciertos campos usando la clave privada RSA de los clientes, una vez que haya llegado a mi servicio, se descifre con la clave pública de los clientes.
En este momento, sigo recibiendo un mensaje de "Los datos que se van a descifrar superan el máximo para este módulo de 128 bytes". excepción. No he tratado mucho con la criptografía C # RSA, por lo que cualquier ayuda sería muy apreciada.
Este es el método que estoy usando para generar las claves.
private void buttonGenerate_Click(object sender, EventArgs e)
{
string secretKey = RandomString(12, true);
CspParameters param = new CspParameters();
param.Flags = CspProviderFlags.UseMachineKeyStore;
SecureString secureString = new SecureString();
byte[] stringBytes = Encoding.ASCII.GetBytes(secretKey);
for (int i = 0; i < stringBytes.Length; i++)
{
secureString.AppendChar((char)stringBytes[i]);
}
secureString.MakeReadOnly();
param.KeyPassword = secureString;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
rsaProvider = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
rsaProvider.KeySize = 1024;
string publicKey = rsaProvider.ToXmlString(false);
string privateKey = rsaProvider.ToXmlString(true);
Repository.RSA_XML_PRIVATE_KEY = privateKey;
Repository.RSA_XML_PUBLIC_KEY = publicKey;
textBoxRsaPrivate.Text = Repository.RSA_XML_PRIVATE_KEY;
textBoxRsaPublic.Text = Repository.RSA_XML_PUBLIC_KEY;
MessageBox.Show("Please note, when generating keys you must sign on to the gateway/n" +
" to exhange keys otherwise transactions will fail", "Key Exchange", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
Una vez que he generado las claves, envío la clave pública al servicio web que la almacena como un archivo XML.
Ahora decidí probar esto, así que aquí está mi método para cifrar una cadena
public static string RsaEncrypt(string dataToEncrypt)
{
string rsaPrivate = RSA_XML_PRIVATE_KEY;
CspParameters csp = new CspParameters();
csp.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(csp);
provider.FromXmlString(rsaPrivate);
ASCIIEncoding enc = new ASCIIEncoding();
int numOfChars = enc.GetByteCount(dataToEncrypt);
byte[] tempArray = enc.GetBytes(dataToEncrypt);
byte[] result = provider.Encrypt(tempArray, true);
string resultString = Convert.ToBase64String(result);
Console.WriteLine("Encrypted : " + resultString);
return resultString;
}
Obtengo lo que parece ser un valor encriptado. En el método de prueba de criptografía web que creé, luego tomo estos datos cifrados, intento descifrar los datos usando la clave pública de los clientes y enviarlos de nuevo en claro. Pero aquí es donde se lanza la excepción. Aquí está mi método responsable de esto.
public string DecryptRSA(string data, string merchantId)
{
string clearData = null;
try
{
CspParameters param = new CspParameters();
param.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(param);
string merchantRsaPublic = GetXmlRsaKey(merchantId);
rsaProvider.FromXmlString(merchantRsaPublic);
byte[] asciiString = Encoding.ASCII.GetBytes(data);
byte[] decryptedData = rsaProvider.Decrypt(asciiString, false);
clearData = Convert.ToString(decryptedData);
}
catch (CryptographicException ex)
{
Log.Error("A cryptographic error occured trying to decrypt a value for " + merchantId, ex);
}
return clearData;
}
Si alguien pudiera ayudarme, sería increíble, como he dicho, no he hecho mucho con el cifrado / descifrado RSA de C #.
En DecryptRSA, ¿la base de datos es 64 codificada? Si es así, tienes que deshacer eso primero.
Honestamente, creo que no debería implementar esa rutina para proteger la "información financiera confidencial", a menos que tenga mucha experiencia con la criptografía. Hay demasiadas formas de cometer errores. ¿Es mejor usar alguna solución preparada, tal vez SSL y certificados, o simplemente PGP o GnuPG?
Entiendo por qué estás haciendo la pregunta. El problema es que RSA no se usa como un cifrado de bloque típico (como AES o 3DES) que cifra 8 bytes a la vez, durante todo el día. RSA es una operación matemática que devuelve el resto de una división (el módulo). De vuelta en la escuela primaria, cuando aprendiste la división larga, recuerda que el resto nunca puede ser mayor que el divisor: si estás dividiendo 20 por 7, el resto es 6. No importa qué número entero dividas por 7, el resto no puede ser mayor de seis.
La matemática RSA es de la misma manera. Por ejemplo, si está utilizando una clave pública RSA de 1024 bits, el resto nunca puede ser mayor que 2 ^ 1024, que es solo de 128 bytes. Por lo tanto, solo puede cifrar 128 bytes a la vez con esta clave. (Esa es una razón por la que medimos el tamaño de las claves RSA por el número de bits).
Técnicamente, podría usar esta clave RSA en un bucle para cifrar fragmentos de 128 bytes de sus datos a la vez. En realidad, casi nunca hacemos esto porque las matemáticas RSA son GRANDES y LENTAS. En su lugar, utilizamos lo que se denomina cifrado "de dos fases". Usamos RSA para cifrar solo una breve "clave de sesión", y luego usamos esa clave de sesión en un cifrado de bloque de clave simétrica (como AES) para cifrar los datos reales.
Todo el protocolo es:
- Obtenga la clave pública RSA de su destino. Esto se entrega a menudo incrustado en un certificado; Si es así, asegúrese de validar el certificado para asegurarse de que la clave sea genuina. Digamos que la clave RSA tiene 2048 bits de longitud.
- Genere un número pseudoaleatorio criptográficamente sólido para usarlo como clave para el cifrado de bloque (necesita 256 bits como la clave para AES-256, por ejemplo). Tenga en cuenta que 256 <2048, el máximo que RSA-2048 puede cifrar de una vez . Llamamos a este número aleatorio la "clave de sesión".
- Cifre la clave de sesión utilizando la clave pública RSA de 2048 bits. Le dará 2048 bits de clave de sesión cifrada. Tenga en cuenta que esta operación es muy lenta.
- Cifre todos los datos secretos usando AES-256, usando la clave de sesión. Tenga en cuenta que esto es mucho más rápido que el paso 3.
- Agrupe la ID de clave pública del certificado, la clave de sesión cifrada RSA y los datos cifrados AES juntos. También lo etiquetaría con un identificador de formato y un número de versión, para que sepa en qué formato está y cómo descifrarlo.
Enviar el paquete al destino.
En el destino, utiliza el identificador de formato y la versión para desarmar el paquete.
- Recupere la clave privada cuya identidad se encuentra en el campo ID de clave pública.
- Utilice esta clave privada en RSA para descifrar la clave de sesión.
- Utilice la clave de sesión en AES para descifrar los datos.
Si va a hacer esto, debe saber que es exactamente para lo que sirve el formato CMS (PKCS # 7). Le animo a que aprenda sobre el estándar y lo adopte, en lugar de intentar inventar su propio formato. El CSP de Microsoft lo admite, por lo que debería ser fácil.
Si no sigue un estándar, tendrá que tomar sus propias decisiones sobre cosas como "¿en qué formato deben estar los bits de clave AES en el proceso de cifrado RSA?" Lo más probable es que, casi con toda seguridad, cometa errores de seguridad, lo que debilita su sistema. Además, encontrará que será muy difícil trabajar con herramientas como el CSP si no sigue un estándar.
Permíteme un poco de terminología. Hay encriptación asimétrica y hay firma digital .
El cifrado asimétrico se trata de mantener la confidencialidad. Algunos datos confidenciales se transforman en algo ilegible, excepto para la entidad que conoce la clave de descifrado. La clave de descifrado es necesariamente la clave privada : si la clave de descifrado es la clave pública, todos pueden descifrar los datos (la clave pública es, bueno, pública) y ya no hay confidencialidad. En el cifrado asimétrico, uno se encripta con la clave pública y se desencripta con la clave privada correspondiente.
Las firmas digitales están destinadas a demostrar la integridad. Alguien calcula un tipo de suma de comprobación con clave sobre los datos, de tal manera que el enlace entre la suma de comprobación y los datos se pueda verificar más adelante. Esta es una "firma" solo porque el poder de calcular esa suma de comprobación requiere el conocimiento de algo que no es público: en pocas palabras, la firma usa la clave privada . Sin embargo, la verificación debe ser factible para cualquiera y, por lo tanto, utilizar la clave pública.
Un poco de confusión está implícita en el hecho de que "el" algoritmo RSA es en realidad una operación matemática que se puede convertir en un sistema de cifrado asimétrico y un sistema de firma digital. La confusión se ve reforzada por el estándar RSA, también conocido como PKCS#1 , que se basa implícitamente en cómo se describieron por primera vez las firmas digitales RSA, es decir, como un "cifrado invertido" ("el firmante cifra los datos con su clave privada"). Lo que lleva a cosas como firmas RSA llamadas "sha1WithRSAEncryption". Esto es bastante desafortunado.
Por lo tanto, primero debe decidir si desea confidencialidad o firmas. Para la confidencialidad, para los datos enviados desde los clientes al servidor, el servidor debe poseer una clave privada, y los clientes utilizan la clave pública del servidor para cifrar los datos. Para las firmas, cada cliente tendrá su propia clave privada y la utilizará para firmar los datos, y el servidor verificará las firmas. Por su descripción, no puedo decir lo que realmente busca, gracias a la confusión a la que aludo más arriba.
Además, hay algo llamado autenticación que puede parecer firmas digitales, pero es más débil. El punto de firmas es que nadie puede verificar la firma. En particular, la firma puede ser mostrada a un juez y, por lo tanto, servir como arma legal contra el firmante (la firma es legalmente vinculante, al menos si lo hace bien y, en el estado actual de las regulaciones sobre firmas electrónicas, esto no es así). fácil). En la mayoría de las situaciones, solo necesita algo más débil y más simple, en el que el servidor esté convencido de que habla con el cliente correcto, pero luego no puede convencer a nadie de que este cliente realmente estaba allí. Cualquier sitio web con contraseñas de usuario está utilizando dicha autenticación.
Con eso dicho...
El cifrado asimétrico RSA cubre solo mensajes cortos. Para una clave RSA de 1024 bits (es decir, una clave donde la parte más importante, el "módulo RSA", es un número grande con un valor entre 2 ^ 1023 y 2 ^ 1024, y los mensajes cifrados tendrán una longitud de 128 bytes), el tamaño máximo de un mensaje cifrado es de 117 bytes (esa es la fuente real de su mensaje de error). Cuando queremos enviar mensajes más largos, utilizamos un sistema híbrido, en el que solo ciframos un pequeño grupo de bits aleatorios (por ejemplo, 128 bits) y utilizamos ese grupo como una clave para un sistema de cifrado simétrico (por ejemplo, AES) que puede procesar mucho Mensajes más largos (y mucho más rápidos, también).
Las firmas RSA, de manera similar, se pueden calcular solo en mensajes cortos, por lo tanto, el estándar PKCS # 1 exige que una firma se calcule en realidad sobre un valor hash. El valor hash es la salida de una función hash específica, que se calcula sobre el mensaje para firmar. La función hash tiene una salida de tamaño fijo (por ejemplo, 256 bits para SHA-256) pero acepta mensajes de entrada de (casi) longitud arbitraria. Las funciones de hash son públicas (no hay ninguna clave en ellas) y, para una seguridad adecuada, deben tener algunas propiedades especiales. SHA-256 es, en este momento, no es una mala elección. Se ha demostrado que SHA-1 (un antecesor de SHA-256) tiene algunas debilidades y debe evitarse. MD5 tiene (un tipo de tío de SHA-1) tiene debilidades más grandes y no debe usarse.
El uso adecuado del cifrado asimétrico, especialmente en un esquema híbrido y firmas digitales, es más complicado de lo que sugiere el texto anterior. Es muy fácil equivocarse en algún momento, de manera invisible , es decir, el código parece funcionar, pero filtrará datos útiles para un atacante. La forma correcta de utilizar el cifrado asimétrico o las firmas digitales es confiar en los protocolos existentes y bien pensados. Un protocolo es un conjunto de elementos criptográficos en un sistema coherente, donde se cuidan las fugas. El primer ejemplo es TLS, también conocido como SSL. Es un protocolo que garantiza la transmisión confidencial de datos, con integridad y autenticación (posiblemente autenticación mutua). El protocolo HTTPS es una mezcla de HTTP y SSL. El lado positivo es que HTTPS tiene implementaciones existentes, especialmente en C #. El código que es más fácil de implementar y depurar es el código que ya se ha implementado y depurado. Así que usa HTTPS y vivirás más y más feliz.
Primero decide contra qué estás tratando de protegerte. Si "encripta" algo con la clave privada, cualquiera puede "descifrarlo" con la clave pública, ya que la clave pública es pública .
Si realmente quiere firmarlo, debe (como explica Paul Alexander) firmar un hash con la clave privada que luego se puede verificar en el servidor.
Para cifrar datos usando RSA, primero debe generar una clave simétrica aleatoria (fx AES), cifrar la clave utilizando una clave pública y cifrar los datos utilizando la clave simétrica. Luego, puede transmitir la clave cifrada junto con los datos cifrados al titular de la clave privada , quien puede descifrar primero la clave cifrada con la clave privada y luego descifrar los datos con la clave simétrica.
También puede considerar el uso de SSL, pero recuerde considerar cuidadosamente la autenticación. Probablemente necesitará la autenticación del cliente y tendrá que decidir en qué certificados confiar (no debe aceptar ciegamente ningún certificado emitido por Verisign).
RSA se utiliza principalmente para validar hashes seguros de datos, en lugar de cifrar los datos en sí. Por lo tanto, dado un gran volumen de datos, puede usar SHA512 para crear un hash de esos datos, y luego usar RSA para firmar ese hash.
Querrá usar un algoritmo de cifrado simétrico para grandes bloques de datos, algo como AES o 3DES.
Administrar transacciones seguras no es fácil y realmente debería dejárselo a aquellos que pasan todo el día y la noche pensando en ello. Si está exponiendo el servicio a través de la web, solo use SSL que ya encripta y protege sus datos.