Criptografía.
Usando las clases de la plataforma .net

Fecha: 16 de Septiembre de 2003 (18/Sep/2003)
Autor: Gonzalo Antonio Sosa M. E-mail


Proveedor de Cifrado.

Antes de comenzar con la clase trataremos de conocer como trabajan los proveedores de cifrado que proporciona la plataforma punto NET. Existen varios proveedores presentes para ser utilizados, proveedores que trabajan basándose en algoritmos de encripción simétricos: conocido como cifrado de bloques, utilizan una misma clave privada para el cifrado y el descifrado de los datos; o asimétricos: utilizan un par de claves, pública y privada, para realizar el cifrado y descifrado; aquí sólo trabajaremos con algunos de ellos. Más específicamente, con aquellos que implementan algoritmos de encripción simétricos:

Como es de suponer funcionan basándose en algoritmos de encripción del que toman sus nombres. Así, DESServiceProvider implementa el algoritmo de encripción DES, TripleDESServiceProvider implementa al algoritmo TripleDES y así sucesivamente.

Acerca de los algoritmos hay que mencionar:

DES:

Es el algoritmo de encripción más extendido mundialmente. Utiliza bloques de 64 bits, los cuales codifica usando claves de 56 bits y aplicando permutaciones a nivel de bit, mediante tablas de permutaciones y operaciones XOR.

TripleDES:

Consiste en aplicar varias veces el algoritmo DES con diferentes claves al mensaje original.

RC2:

Permite definir el tamaño del bloque a encriptar, el tamaño de la clave utilizada y el número de fases de encriptación.

Rijndael:

Posee una estructura en capas formadas por funciones polinómicas reversibles (tienen inversa) y no lineales.

Bien, ahora nos toca implementar el encapsulado de los proveedores de cifrado. De lo que se trata es de crear dos clases genéricas, una de ellas, la que se implementa aquí, contendrá un método que devolverá al proveedor apropiado para ser utilizado en la clase que codificaremos más adelante.

La clase ha sido nombrada CryptoServiceProvider, y la codificación se define a continuación:

Importamos los namespaces necesarios:

using System;
using System.Security.Cryptography;


Puesto que esta clase no podrá ser vista por el usuario final, únicamente podrá ser invocada por la siguiente clase que codificaremos, el modificador de acceso que por default es public, pasará a ser internal.

internal class CryptoServiceProvider {

Utilizamos dos enumeraciones internas para conocer tanto al proveedor de encripción seleccionado, como para saber que acción (cifrado o descifrado) estamos realizando. Estas se almacenaran en dos variables privadas globales destinada a tal fin.

// proveedor de cifrado.
private CryptoProvider algorithm;
// acción a realizar
private CryptoAction cAction;

// Lista con las posibles acciones a realizar dentro de la clase.
internal enum CryptoAction
{
    Encrypt,  // Cifrar
    Desencrypt  // Descifrar
}

// Lista con los proveedores de cifrado que proporciona la clase.
internal enum CryptoProvider
{
    DES,
    TripleDES,
    RC2,
    Rijndael
}

Al constructor de la clase igualmente establecemos el modificador de acceso a internal. Será mediante el constructor que estableceremos al proveedor de cifrado así como definiremos la acción a realizar; esto mediante dos parámetros del constructor.

/// <summary>
/// Contructor por defecto.
/// </summary>
/// <param name="alg">Proveedor (algoritmo) seleccionado.</param>
/// <param name="action">Acción a realizar.</param>
internal CryptoServiceProvider(CryptoProvider alg, CryptoAction action)
{
    // asignamos las opciones seleccionadas.
    // proveedor (algoritmo) de encripción y acción a realizar.
    this.algorithm = alg;
    this.cAction = action;
}

Antes de comenzar con la codificación del único método presente en la clase, debemos comprender que para poder realizar el cifrado de los datos, las clases de criptografía simétrica utilizan un flujo especial llamado: CrytoStream, el cual cifra los datos leídos de una secuencia proporcionada. Esta secuencia puede ser cualquiera que derive de la clase Stream: FileStream, MemoryStream y NetworkStream. Por otro lado, CryptoStream se inicializa, además de la secuencia mencionada, con una clase que implemente la interfaz ICryptoTransform y una enumeración del tipo CryptoStreamMode, que describe el acceso permitido a CryptoStream

Para nuestro caso, el método implementado en la clase CryptoServiceProvider, se encargará de devolvernos un objeto ya inicializado de ICryptoTransform. La inicialización se realiza proporcionando, además del tipo de proveedor seleccionado, pasando como parámetros del método, los valores de la clave privada: la clave secreta del algoritmo simétrico; y del vector de inicialización: Vector de inicialización del algoritmo simétrico. Cuando definimos un proveedor de encripción, utilizamos a dicho proveedor para crear un objeto cifrador o descifrador, de la clase del proveedor seleccionado.

Todos los algoritmo simétricos necesitan de una clave secreta y de un vector de inicialización para realizar el cifrado, explicar que propósito tiene cada uno tomaría mucho tiempo, lo único que debo mencionar al respecto es que al momento de crear los objetos cifradores o descifradores, debemos proporcionar dicha clave y vector de inicialización en forma de arreglo de bytes (byte array) y no como cadenas de caracteres. Se puede omitir alguna de ellas o ambas, entonces dichos valores son generados aleatoriamente. 

/// <summary>
/// Define un objeto para la operaciones básicas de transformaciones
/// criptográficas.
/// </summary>
/// <param name="Key">Clave de encripción.</param>
/// <param name="IV">Vector de inicialización.</param>
/// <returns>Devuelve el objeto que implementa la interfaz ICryptoTransform.
/// </returns>
internal ICryptoTransform GetServiceProvider(byte[] Key, byte[] IV)
{
    // creamos la variable que contendrá al objeto ICryptoTransform.
    ICryptoTransform transform = null;

    // dependiendo del algoritmo seleccionado, se devuelve el objeto adecuado.
    switch (this.algorithm)
    {
        // Algoritmo DES.
        case CryptoProvider.DES:
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            // dependiendo de la acción a realizar.
            // creamos el objeto adecuado.
            switch (cAction)
            {
                case CryptoAction.Encrypt:  // si estamos cifrando,
                    // creamos el objeto cifrador. 
                    transform = des.CreateEncryptor(Key, IV);
                    break;
                case CryptoAction.Desencrypt: // sí estamos descifrando,
                    // creamos el objeto descifrador.
                    transform = des.CreateDecryptor(Key, IV);
                break;
            }
            return transform;  // devolvemos el objeto transform correspondiente.
        // algoritmo TripleDES.
        case CryptoProvider.TripleDES:
            TripleDESCryptoServiceProvider des3 = new TripleDESCryptoServiceProvider();
            switch (cAction)
            {
                case CryptoAction.Encrypt:
                    transform = des3.CreateEncryptor(Key, IV);
                    break;
                case CryptoAction.Desencrypt:
                    transform = des3.CreateDecryptor(Key, IV);
                break;
            }
            return transform;
        // algoritmo RC2.
        case CryptoProvider.RC2:
            RC2CryptoServiceProvider rc2 = new RC2CryptoServiceProvider();
            switch (cAction)
            {
                case CryptoAction.Encrypt:
                    transform = rc2.CreateEncryptor(Key, IV);
                    break;
                case CryptoAction.Desencrypt:
                    transform = rc2.CreateDecryptor(Key, IV);
                    break;
            }
            return transform;
        // algoritmo Rijndael.
        case CryptoProvider.Rijndael:
            Rijndael rijndael = new RijndaelManaged();
            switch (cAction)
            {
                case CryptoAction.Encrypt:
                    transform = rijndael.CreateEncryptor(Key, IV);
                    break;
                case CryptoAction.Desencrypt:
                    transform = rijndael.CreateDecryptor(Key, IV);
                    break;
            }
        return transform;
default:
    // en caso que no exista el proveedor seleccionado, generamos
    // una excepción para informarlo.
    throw new CryptographicException("Error al inicializar al proveedor de cifrado");
   }
}

Con esto habremos terminado con la clase Proveedor  del servicio criptográfico. La siguiente clase, que hará uso de esta, se encargará de la parte detallada del cifrado.

 

Anterior

Principal

Siguiente


ir al índice