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.