2010-01-27 19 views
10

Estoy buscando una rutina simétrica de cifrado/descifrado en C#. Sé que ha habido algunas preguntas sobre este tema antes, pero la mayoría de las respuestas parecen ser sobre la filosofía del cifrado en lugar de dar un código real.Cifrado/descifrado simétrico en .NET

Actualización: Realmente me gustaría ver algunos códigos, en lugar de enlaces. ¡Muchas gracias!

+1

¿Rijndael no es simétrico? –

+0

Creo que es –

+1

Yo recomendaría usar Rijndael, entonces :) –

Respuesta

11

Mire el código de ejemplo en la parte inferior de this page.

copiar y pegar aquí:

int Rfc2898KeygenIterations= 100; 
int AesKeySizeInBits = 128; 
String Password = "VerySecret!"; 
byte[] Salt = new byte[16]; 
System.Random rnd = new System.Random(); 
rnd.NextBytes(Salt); 
byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!"); 
byte[] cipherText= null; 
byte[] plainText= null; 
using (Aes aes = new AesManaged()) 
{ 
    aes.Padding = PaddingMode.PKCS7; 
    aes.KeySize = AesKeySizeInBits; 
    int KeyStrengthInBytes= aes.KeySize/8; 
    System.Security.Cryptography.Rfc2898DeriveBytes rfc2898 = 
     new System.Security.Cryptography.Rfc2898DeriveBytes(Password, Salt, Rfc2898KeygenIterations); 
    aes.Key = rfc2898.GetBytes(KeyStrengthInBytes); 
    aes.IV = rfc2898.GetBytes(KeyStrengthInBytes); 
    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write)) 
     { 
      cs.Write(rawPlaintext, 0, rawPlaintext.Length); 
     } 
     cipherText= ms.ToArray(); 
    } 

    using (MemoryStream ms = new MemoryStream()) 
    { 
     using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write)) 
     { 
      cs.Write(cipherText, 0, cipherText.Length); 
     } 
     plainText = ms.ToArray(); 
    } 
} 
string s = System.Text.Encoding.Unicode.GetString(plainText); 
Console.WriteLine(s); 
+5

Ewww, usando el Random no seguro para crear la sal? Mala mala idea – blowdart

+6

@blowdart - No. La sal y la IV deben ser tan únicas como sea posible, pero generarlas de forma segura no significa nada. Seguro aleatorio significa aleatorio que es difícil de predecir, y no le importa si su IV o sal están pronosticadas; de todos modos, se pasan/almacenan en texto plano. – orip

+0

@blowdart - concedo su punto sobre IV en modo CBC. Sin embargo, no vale para la sal en PBKDF2. – orip

2

convierta el mensaje, clave y el vector de inicialización a bytes primero utilizando la codificación de su elección. A continuación, utilice el proveedor de triple DES, como se ha demostrado aquí:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.tripledes.aspx

O el uno para AES, si se piensa triple DES es demasiado vieja escuela, o lo que sea.

Por curiosidad, ¿cómo piensas comunicar la clave secreta?

+1

¿Está intentando cifrar datos para evitar que el usuario los lea? –

+0

Para DES, la clave y IV pueden ser cualquier cadena de caracteres, ¿verdad? –

+5

La codificación de la clave en el origen de una aplicación .NET es insegura. Todo lo que el usuario tiene que hacer es descargar Reflector y la clave está ahí a la vista. –

5

Bueno, para empezar, las teclas no son cadenas, las teclas son blobs binarios. PlainText es lo mismo, en realidad no es texto, de nuevo es un blob binario.

Ahora, por supuesto, se puede convertir cadenas en matrices de bytes utilizando Encoding.UTF8.GetBytes(message), sin embargo, cuando la conversión de llaves de ida y vuelta que es un poco más complicado, que suelen utilizar Convert.ToBase64String y Convert.FromBase64String.

No olvide que las cifras de bloque también tienen una cosa más, el vector de inicialización, así que realmente sus firmas de método debe ser

byte[] Encrypt(byte[] plainText, byte[] key, byte[] iv) 

byte[] Decrypt(byte[] cipherText, byte[] key, byte[] iv) 

La clave y vías intravenosas debe ser números aleatorios criptográficamente seguros, don' Simplemente escríbalos y no use la función aleatoria de C#. El tamaño de la clave y el IV dependen del algoritmo de cifrado utilizado, y las propiedades de las clases pueden acceder a él.

Para generar un CSRPNG haces algo como

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
byte[] key = new byte[algorithm.KeySizeValue/8]; 
rng.GetBytes(key); 
byte[] iv = new byte[algorithm.BlockSizeValue/8]; 
rng.GetBytes(iv); 

También puede utilizar la clase Rfc2898DeriveBytes para derivar una clave y IV de una contraseña y una sal, pero de nuevo la sal debe ser un número aleatorio criptográficamente seguro . También debe tener en cuenta que cuando crea un algoritmo simétrico se genera una clave segura y IV para usted.

De esta manera, puede elegir la codificación correcta para su texto, ya sea UTF8, ASCII o lo que sea. Los enlaces tienen suficientes muestras para cortar y pegar aquí es bastante inútil.

+1

Los IV no necesitan ser criptográficamente seguros, solo las teclas sí. – orip

+1

No es cierto, en modo CBC, el IV debe ser impredecible en el momento del cifrado – blowdart

+1

Gracias, no estaba enterado de eso. – orip

4

Aquí hay una solución sencilla que he encontrado en un foro de VB.NET y se convierte en C#. Ciertamente me ayudó a entender mejor el tema.

// Shamelessly lifted from http://discuss.itacumens.com/index.php?topic=62872.0, 
// then converted to C# (http://www.developerfusion.com/tools/convert/vb-to-csharp/) and 
// changed where necessary. 
public class Encryptor 
{ 
    private static SymmetricAlgorithm _cryptoService = new TripleDESCryptoServiceProvider(); 
    // maybe use AesCryptoServiceProvider instead? 

    // vector and key have to match between encryption and decryption 
    public static string Encrypt(string text, byte[] key, byte[] vector) 
    { 
     return Transform(text, _cryptoService.CreateEncryptor(key, vector)); 
    } 

    // vector and key have to match between encryption and decryption 
    public static string Decrypt(string text, byte[] key, byte[] vector) 
    { 
     return Transform(text, _cryptoService.CreateDecryptor(key, vector)); 
    } 

    private static string Transform(string text, ICryptoTransform cryptoTransform) 
    { 
     MemoryStream stream = new MemoryStream(); 
     CryptoStream cryptoStream = new CryptoStream(stream, cryptoTransform, CryptoStreamMode.Write); 

     byte[] input = Encoding.Default.GetBytes(text); 

     cryptoStream.Write(input, 0, input.Length); 
     cryptoStream.FlushFinalBlock(); 

     return Encoding.Default.GetString(stream.ToArray()); 
    } 
}