Fly and Enjoy .Net!

Un espacio para compartir la experiencia del desarrollo de aplicaciones

Criptografía: Algoritmos Simétricos
Quizá en algún momento se han hecho preguntas del tipo ¿cómo podríamos proteger la información sensitiva de mi aplicación?, ¿qué pasa si leen mi cadena de conexión al tener acceso al archivo de configuración?, sin duda que cada una de las respuestas nos lleva a considerar alguna opción que incremente el nivel de seguridad y que toda esta información no pueda ser interpretada en caso de ser leída.  
 
Por esta y razones más, en esta ocasión continuaremos con el tema de criptografía y ahora lo hacemos para platicar acerca de algoritmos criptográficos. La labor de este tipo de algoritmos será realizar operaciones matemáticas con los datos originales y una llave de por medio, el resultado de esos cálculos son los datos encriptados.
 
Para poder implementar este tipo de algoritmos, tenemos dos opciones: algoritmos simétricos y asimétricos. Los algoritmos simétricos encriptan y desencriptan con la misma llave, mientras que los asimétricos utilizan diferentes llaves.  En esta nota nos enfocaremos a los algoritmos simétricos y en próximas entregas platicaremos de algoritmos asimétricos.
 
Algunos de los algoritmos simétricos comunes son:
 
·         DES
·         3DES
·         RC2
·         Rijndael
 
Y su implementación en .NET Framework la tenemos disponible a través de las siguientes clases:
 
·         DES (DESCryptoServiceProvider),
·         TripleDES (TripleDESCryptoServiceProvider),
·         RC2 (RC2CryptoServiceProvider) y
·         Rijndael (RijndaelManaged).
 
De las clases anteriores, la implementación del algoritmo Rijndael es completamente administrada, mientras que las otras opciones no lo son del todo, debido a que hacen llamadas a código no administrado gracias a que se comunican con api’s del sistema operativo.
 
Y después de esta teoría, la cual siempre es necesaria, llega el momento de la práctica. Así que vamos a realizar un ejemplo para revisar de manera sencilla la implementación de estos algoritmos.  
 
Así que comencemos:
 
1.       Creamos un proyecto de aplicación Windows en el lenguaje de su preferencia, con una presentación como la que muestra la figura.
 
 
2.   Ahora en nuestro código, importamos el espacio de nombres System.Security.Cryptography para tener acceso a las clases de algoritmos simétricos
 
VB
Imports System.Security.Cryptography
 
CS
     using System.Security.Cryptography;
 
3.      Definimos en nuestra clase a nuestro proveedor de la encriptación, el cual será del tipo SymmetricAlgorithm.
 
VB
Private alg As SymmetricAlgorithm
 
CS
private SymmetricAlgorithm alg;
 
4.       En el constructor de la clase realizamos la instancia de nuestro algoritmo simétrico, que para este caso es implementación de Rijndael, pero bien puede ser cualquiera de las otras opciones previamente mencionadas.
 
VB
Public Sub New()
 
        InitializeComponent()
        alg = New RijndaelManaged
 
End Sub
 
CS
public Form1()
{
         InitializeComponent();
         alg = new RijndaelManaged();
}
 
5.      Como se mencionó, para poder realizar la encriptación, se requiere de una llave, pues está será parte del rol principal para poder encriptar y desencriptar en los algoritmos simétricos. La característica de esta llave dependerá del tipo de algoritmo utilizado, aquí una breve descripción de las llaves de acuerdo al tipo de algoritmo:
 
Algoritmo
tamaño (bits)
Default (bits)
DES
64
64
TripleDES
128, 192
192
RC2
40 – 128
128
RijndaelX
128, 192, 256
256
 
Para la generación de la llave, incluimos la llamada al método GenerateKey().
 
 
VB
Private Sub btnGenerarLlave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGenerarLlave.Click
 
        alg.GenerateKey()
        textLlave.Text = Convert.ToBase64String(alg.Key)
 
End Sub
 
CS
private void btnGenerarLlave_Click(object sender, EventArgs e)
{
        alg.GenerateKey();
        textLlave.Text = Convert.ToBase64String(alg.Key);
 
}
 
6.      Una vez que se crea la llave, el siguiente paso será la creación de un vector de inicialización, también conocido como IV, el cual sin ir tan a detalle es un bloque de bits requerido para el proceso de encriptación, el cual trabajará en conjunto con la llave para obtener el valor cifrado. Es importante hacer evidente que para todo proceso de encriptación es recomendable cambiar el valor de este vector, sino el resultado de las encriptaciones podría producir resultados similares, los cuales pudieran facilitar la labor del desciframiento de los datos.
 
VB
Private Sub btnGenerarVector_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGenerarVector.Click
       
alg.GenerateIV()
     textVector.Text = Convert.ToBase64String(alg.IV)
 
End Sub
 
 
CS
private void btnGenerarVector_Click(object sender, EventArgs e)
{
       alg.GenerateIV();
       textVector.Text = Convert.ToBase64String(alg.IV);
}
 
7.      El siguiente paso, es definir un método para hacer la labor de encriptación; en el cual podemos distinguir la definición de algunas clases que participan en este proceso, como un MemoryStream que trabajará en conjunto con CryptoStream para la encriptación de los datos.
 
VB
Private Function Encriptar(ByVal textoplano As Byte()) As Byte()
 
        Dim ct As ICryptoTransform
        Dim ms As System.IO.MemoryStream
        Dim cs As CryptoStream
 
        ct = alg.CreateEncryptor(alg.Key, alg.IV)
        ms = New System.IO.MemoryStream
        cs = New CryptoStream(ms, ct, CryptoStreamMode.Write)
 
        cs.Write(textoplano, 0, textoplano.Length)
        cs.FlushFinalBlock()
        Return ms.ToArray
 
End Function
 
 
CS
private byte[] Encriptar(byte[] textoPlano)
{
 
    ICryptoTransform cp = alg.CreateEncryptor(alg.Key, alg.IV);
    MemoryStream ms = new MemoryStream();
    CryptoStream cs = new CryptoStream(ms, cp, CryptoStreamMode.Write);
          
    cs.Write(textoPlano, 0, textoPlano.Length);
    cs.FlushFinalBlock();
    return ms.ToArray();
           
}
 
En el código anterior podemos darnos cuenta del uso inminente de la llave y el vector de inicialización generado, para posteriormente trabajar con el arreglo de bytes del texto a encriptar.
 
8.      Ahora, podemos mandar llamar el método Encriptar y para hacerlo damos clic en el botón "Encriptar" para definir el siguiente código:
 
Private Sub btnEncriptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEncriptar.Click
 
        Dim textooriginal() As Byte
        Dim textocifrado() As Byte
 
        textooriginal = System.Text.Encoding.UTF8.GetBytes(textValor.Text)
        textocifrado = Encriptar(textooriginal)
        textResultado.Text = Convert.ToBase64String(textocifrado)
 
End Sub
 
CS
private void btnEncriptar_Click(object sender, EventArgs e)
{
           
byte[] textoOriginal;
     byte[] textoCifrado;
     textoOriginal = System.Text.Encoding.UTF8.GetBytes(textValor.Text);
     textoCifrado = Encriptar(textoOriginal);
     textResultado.Text = Convert.ToBase64String(textoCifrado);
       
}
 
9.      Ahora, para poder interpretar la información y descifrar los datos, realizamos la definición del siguiente método.
 
VB
Private Function Desencriptar(ByVal textocifrado As Byte()) As Byte()
 
        Dim ct As ICryptoTransform
        Dim ms As System.IO.MemoryStream
        Dim cs As CryptoStream
        Dim buffer(textocifrado.Length) As Byte
 
 
        ct = alg.CreateDecryptor(alg.Key, alg.IV)
        ms = New System.IO.MemoryStream(textocifrado)
        cs = New CryptoStream(ms, ct, CryptoStreamMode.Read)
 
        cs.Read(buffer, 0, buffer.Length)
        ms.Close()
        cs.Close()
        Return buffer
 
End Function
 
CS
private byte[] Desencriptar(byte[] textoCifrado)
{
           
   ICryptoTransform cp = alg.CreateDecryptor(alg.Key, alg.IV);
   MemoryStream ms = new MemoryStream(textoCifrado);
   CryptoStream cs = new CryptoStream(ms, cp, CryptoStreamMode.Read);
   byte[] buffer = new byte[textoCifrado.Length];
   cs.Read(buffer, 0, buffer.Length);
   ms.Close();
   cs.Close();
   return buffer;
       
}
 
En este método notamos como aparecen las mismas clases que participan en el proceso de encriptación; solamente que ahora trabajaremos en modo de lectura y así poder devolver como resultado final el valor original de los datos cifrados.
 
10.  Ahora, llamamos nuestro método Desencriptar y para esto definimos el siguiente código en el clic del botón "Desencriptar".
 
VB
Private Sub btnDesencriptar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDesencriptar.Click
 
        Dim textooriginal() As Byte
        Dim textocifrado() As Byte
 
        textocifrado = Convert.FromBase64String(textResultado.Text)
        textooriginal = Desencriptar(textocifrado)
        textInicial.Text = System.Text.Encoding.UTF8.GetString(textooriginal)
 
    End Sub
 
CS
private void btnDesencriptar_Click(object sender, EventArgs e)
{
 
    byte[] textoCifrado;
    byte[] textoOriginal;
 
    textoCifrado = Convert.FromBase64String(textResultado.Text);
    textoOriginal = Desencriptar(textoCifrado);
    textInicial.Text = System.Text.Encoding.UTF8.GetString(textoOriginal);
       
}
 
11.  Llega el momento de ejecutar nuestro ejemplo y como valor inicial escribo el valor de Password.
 
Para realizar la encriptación, primero generamos la llave y el vector de inicialización, posterior a esto damos clic en la acción de Encriptar y vemos el resultado en la caja de texto del valor cifrado. Listo! para este momento ya tenemos nuestro valor original completamente modificado.
 
Ahora, para descifrar los datos y conocer cual es el valor original, damos clic en la acción de desencriptar y observamos el resultado que debe ser equivalente al valor inicial, en este caso para el ejemplo debe ser el valor de Password.
 
 
Y es así como de manera sencilla hemos revisado como implementar algoritmos simétricos para la encriptación de datos.
 
Espero que esta nota sea de utilidad y como siempre los invito a agregar aspectos de seguridad a su desarrollo cotidiano.
 
Es un gusto compartir. Nos encontramos en la próxima.
 
Published Tuesday, May 22, 2007 4:48 PM por Marcos
Archivado en: ,

Comentarios

# re: Criptografía: Algoritmos Simétricos@ Friday, August 10, 2007 6:12 PM

Marcos, quisiera hacerte una consulta mas que un comentario, he leido de algunos de estos algoritmos simetricos tienen dos tipos de encriptacion: cifrado por bloques y por stream's, sin embargo no he podido encontrar nigun ejemplo de cifrado por bloques, como sabras, en este tipo la longitud del texto plano es igual a la longitud del texto cifrado, y es usado con caracteres hexadecimales, yo lo requiero para trabajar con dispositivos como POS, los cuales realizan este tipo de encriptacion y usan DES para el mismo, encriptan 16 caracteres hexadecimales en otros 16 caracteres hexadecimales, sin embargo yo he probado otros ejemplos con DES incluso el tuyo cambiando el algoritmo a DES y no puedo obtener ese tipo de cifrado por bloques, es posible que tu tengas un ejemplo de esto, gracias

# re: Criptografía: Algoritmos Simétricos@ Tuesday, May 06, 2008 8:08 AM

Hola Marcos!!! Me gustaría saber si hay alguna forma de almacenar una clave privada dentro de un assembly de manera segura.

Estoy intentando encriptar la comunicación entre un objeto COM y otro .Net y para ello quiero utilizar un algoritmo simetrico,

que ambos objetos conozcan la clave privada. Utilizando Reflector es muy fácil sacar la clave.

Hay alguna forma de proteger esa información dentro del assembly????? Ofuscar el código es la única forma de proteger esa información????

Gracias

by jungui