Cifrado y descifrado simétrico con Rijndael (AES) utilizando C#/Mono
Cifrado y descifrado simétrico con Rijndael (AES) utilizando C#/Mono – Jorge Iván Meza Martínez
Introducción.
El cifrador fue desarrollado por dos criptólogos belgas, Joan Daemen y Vincent Rijmen, ambos estudiantes de la Katholieke Universiteit Leuven, y enviado al proceso de selección AES bajo el nombre “Rijndael”.
Tomado del artículo Advanced Encryption Standard de Wikipedia.
Implementación con strings.
La aplicación de demostración de esta técnica requiere del uso de por lo menos los siguientes namespaces.
using System; using System.Security.Cryptography; using System.Text; using System.IO;
Establecer la clave y el vector de inicio.
Estos valores pueden ser especificados manualmente o de manera automática por el framework. La implementación para permitir que se definan automáticamente estos valores es la siguiente.
Rijndael rijndael = Rijndael.Create(); byte[] key = rijndael.Key; byte[] iv = rijndael.IV;
Es posible forzar la generación de nuevas claves y nuevos vectores de inicio para el algoritmo utilizando los métodos rijndael.GenerateKey() y rijndael.GenerateIV() respectivamente.
Si por el contrario se desea especificar estos valores manualmente su implementación es la siguiente siendo strKey y strIv, la clave y el vector de inicialización como cadenas de texto.
byte[] key = UTF8Encoding.UTF8.GetBytes(strKey); byte[] iv = UTF8Encoding.UTF8.GetBytes(strIv);
Especificando estos valores manualmente es necesario garantizar que sus longitudes sean válidas para el algoritmo. En este caso se utilizará una longitud de clave de 32 bits y una longitud de vector de inicio de 16 bits.
int keySize = 32; int ivSize = 16; Array.Resize(ref key, keySize); Array.Resize(ref iv, ivSize);
Cifrado de cadenas de texto.
Para cifrar la información se requiere de los siguientes parámetros.
- Cadena de texto con los datos a cifrar.
- Clave.
- Vector de inicio.
El proceso retornará finalmente una cadena de texto con los datos cifrados.
/** * Cifra una cadena texto con el algoritmo de Rijndael * * @param plainMessage mensaje plano (sin cifrar) * @param Key clave del cifrado para Rijndael * @param IV vector de inicio para Rijndael * @return string texto cifrado */ public static string encryptString(String plainMessage, byte[] Key, byte[] IV) { // Crear una instancia del algoritmo de Rijndael Rijndael RijndaelAlg = Rijndael.Create(); // Establecer un flujo en memoria para el cifrado MemoryStream memoryStream = new MemoryStream(); // Crear un flujo de cifrado basado en el flujo de los datos CryptoStream cryptoStream = new CryptoStream(memoryStream, RijndaelAlg.CreateEncryptor(Key, IV), CryptoStreamMode.Write); // Obtener la representación en bytes de la información a cifrar byte[] plainMessageBytes = UTF8Encoding.UTF8.GetBytes(plainMessage); // Cifrar los datos enviándolos al flujo de cifrado cryptoStream.Write(plainMessageBytes, 0, plainMessageBytes.Length); cryptoStream.FlushFinalBlock(); // Obtener los datos datos cifrados como un arreglo de bytes byte[] cipherMessageBytes = memoryStream.ToArray(); // Cerrar los flujos utilizados memoryStream.Close(); cryptoStream.Close(); // Retornar la representación de texto de los datos cifrados return Convert.ToBase64String(cipherMessageBytes); }
Descifrado de cadenas de texto.
El proceso inverso, el de descifrado, se realiza de manera antagónica. Para hacerlo es necesario contar con los siguientes parámetros.
- Cadena de texto con los datos cifrados.
- Clave.
- Vector de inicio.
El proceso retornará finalmente una cadena de texto con los datos descifrados.
/** * Descifra una cadena texto con el algoritmo de Rijndael * * @param encryptedMessage mensaje cifrado * @param Key clave del cifrado para Rijndael * @param IV vector de inicio para Rijndael * @return string texto descifrado (plano) */ public static string decryptString(String encryptedMessage, byte[] Key, byte[] IV) { // Obtener la representación en bytes del texto cifrado byte[] cipherTextBytes = Convert.FromBase64String(encryptedMessage); // Crear un arreglo de bytes para almacenar los datos descifrados byte[] plainTextBytes = new byte[cipherTextBytes.Length]; // Crear una instancia del algoritmo de Rijndael Rijndael RijndaelAlg = Rijndael.Create(); // Crear un flujo en memoria con la representación de bytes de la información cifrada MemoryStream memoryStream = new MemoryStream(cipherTextBytes); // Crear un flujo de descifrado basado en el flujo de los datos CryptoStream cryptoStream = new CryptoStream(memoryStream, RijndaelAlg.CreateDecryptor(Key, IV), CryptoStreamMode.Read); // Obtener los datos descifrados obteniéndolos del flujo de descifrado int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length); // Cerrar los flujos utilizados memoryStream.Close(); cryptoStream.Close(); // Retornar la representación de texto de los datos descifrados return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount); }
Implementación con archivos.
El cifrado y descifrado de mensajes en archivos se realiza de manera similar al expuesto anteriormente con cadenas, sin embargo varían los flujos (streams) utilizados para obtener y dirigir el flujo de la información.
Cifrado a archivos.
/** * Cifra una cadena texto con el algoritmo de Rijndael y lo almacena en un archivo * * @param plainMessage mensaje plano (sin cifrar) * @param filename nombre del archivo donde se almacenará el mensaje cifrado * @param Key clave del cifrado para Rijndael * @param IV vector de inicio para Rijndael * @return void */ public static void encryptToFile(String plainMessage, String filename, byte[] Key, byte[] IV) { // Crear un flujo para el archivo a generarse FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate); // Crear una instancia del algoritmo Rijndael Rijndael RijndaelAlg = Rijndael.Create(); // Crear un flujo de cifrado basado en el flujo de los datos CryptoStream cryptoStream = new CryptoStream(fileStream, RijndaelAlg.CreateEncryptor(Key, IV), CryptoStreamMode.Write); // Crear un flujo de escritura basado en el flujo de cifrado StreamWriter streamWriter = new StreamWriter(cryptoStream); // Cifrar el mensaje a través del flujo de escritura streamWriter.WriteLine(plainMessage); // Cerrar los flujos utilizados streamWriter.Close(); cryptoStream.Close(); fileStream.Close(); }
Descifrado de archivos.
/** * Descifra el contenido de un archivo con el algoritmo de Rijndael y lo retorna * como una cadena de texto plano * * @param filename nombre del archivo donde se encuentra el mensaje cifrado * @param Key clave del cifrado para Rijndael * @param IV vector de inicio para Rijndael * @return string mensaje descifrado (plano) */ public static string decryptFromFile(String filename, byte[] Key, byte[] IV) { // Crear un flujo para el archivo a generarse FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate); // Crear una instancia del algoritmo Rijndael Rijndael RijndaelAlg = Rijndael.Create(); // Crear un flujo de cifrado basado en el flujo de los datos CryptoStream cryptoStream = new CryptoStream(fileStream, RijndaelAlg.CreateDecryptor(Key, IV), CryptoStreamMode.Read); // Crear un flujo de lectura basado en el flujo de cifrado StreamReader streamReader = new StreamReader(cryptoStream); // Descifrar el mensaje a través del flujo de lectura string plainMessage = streamReader.ReadLine(); // Cerrar los flujos utilizados streamReader.Close(); cryptoStream.Close(); fileStream.Close(); return plainMessage; } Cifrado y descifrado simétrico con Rijndael (AES) utilizando C#/Mono – Jorge Iván Meza Martínez
Aplicación de demostración.
La aplicación de demostración incluye los conceptos y el código expuestos en este artículo. Con ella es posible cifrar y descifrar un mensaje que consiste en una cadena de texto arbitraria en memoria y en un archivo.
Construír la aplicación.
La aplicación de demostración puede construírse utilizando la solución incluída en la distribución con MonoDevelop o Visual Studio. También es posible construírla desde línea de comando (Mono) mediante la siguiente instrucción.
$ gmcs “/out:RijndaelSample.exe” “/r:/usr/lib/mono/2.0/System.dll” /t:exe “RijndaelSample/Main.cs”
Enlaces.
- Aplicación de demostración del cifrado Rijndael (AES) de cadenas y archivos.
http://demo.jorgeivanmeza.com/NET/Rijndael-AES-Sample/ - Advanced Encryption Standard – AES (Rijndael).
http://es.wikipedia.org/wiki/Advanced_Encryption_Standard - AES Algoritm information.
http://csrc.nist.gov/archive/aes/rijndael/wsdindex.html - Rijndael Class en MSDN.
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx - How To: Encrypt and Decrypt Data Using a Symmetric (Rijndael) Key (C#/VB.NET).
http://www.obviex.com/samples/Encryption.aspx
http://blog.jorgeivanmeza.com/2010/10/cifrado-y-descifrado-simetrico-con-rijndael-aes-utilizando-cmono/