Cómo: Crear una biblioteca de cifrado

Publicado: 26 de junio de 2006

Consulte la Página de entrada como punto de partida y para obtener una descripción completa del documento Crear aplicaciones ASP.NET seguras.

Resumen: En este artículo se muestra cómo crear una biblioteca de clases administradas para proporcionar funcionalidad de cifrado para las aplicaciones. Permite que una aplicación elija el algoritmo de cifrado. Entre los algoritmos admitidos se incluyen DES, Triple DES, RC2 y Rijndael.

En este artículo se describe cómo crear una biblioteca de cifrado genérica que se puede utilizar para cifrar y descifrar datos con los siguientes algoritmos:
DES (Digital Encryption Standard, Estándar de cifrado digital)

Triple DES
Rijndael
RC2

Si desea ver un ejemplo de aplicación en la que se utiliza la biblioteca de clases que se crea en este artículo, consulte "Cómo: Almacenar cadenas de conexión cifradas en el Registro" en la sección Referencia de esta guía.

Requisitos

A continuación se describen las recomendaciones de hardware, software, infraestructura de red, conocimientos y Service Pack que se necesitan.

  • Sistema operativo Microsoft® Windows® 2000

  • Crear una biblioteca de clases en C#

  • Crear una aplicación de prueba de consola

En esta página

Crear una biblioteca de clases en C# Crear una biblioteca de clases en C#
Crear una aplicación de prueba de consola Crear una aplicación de prueba de consola
Referencias Referencias

Crear una biblioteca de clases en C#

En este procedimiento se crea una biblioteca de clases en C# que proporcionará funcionalidad de cifrado y descifrado.

Para crear una biblioteca de clases en C#

  1. Inicie Visual Studio .NET y cree un nuevo proyecto de biblioteca de clases de C# con el nombre Encryption.

  2. Utilice el Explorador de soluciones para cambiar el nombre del archivo class1.cs por EncryptTransformer.cs.

  3. En el archivo EncryptTransformer.cs, cambie el nombre de Class1 por EncryptTransformer.

  4. Cambie el ámbito de la clase de public a internal.

    internal class EncryptTransformer
    
  5. Agregue la siguiente instrucción using al principio del archivo.

    using System.Security.Cryptography;
    
  6. Agregue el siguiente tipo enumerado en el espacio de nombres Encryption.

    public enum EncryptionAlgorithm {Des = 1, Rc2, Rijndael, TripleDes};
    
  7. Agregue a la clase EncryptTransformer las siguientes variables miembro privadas.

    private EncryptionAlgorithm algorithmID;
       private byte[] initVec;
       private byte[] encKey;
    
  8. Reemplace el constructor predeterminado por el siguiente constructor.

    internal EncryptTransformer(EncryptionAlgorithm algId)
       {
       //Save the algorithm being used.
       algorithmID = algId;
       }
    
  9. Agregue a la clase el método siguiente.

    internal ICryptoTransform GetCryptoServiceProvider(byte[] bytesKey)
       {
       // Pick the provider.
       switch (algorithmID)
       {
       case EncryptionAlgorithm.Des:
       {
       DES des = new DESCryptoServiceProvider();
       des.Mode = CipherMode.CBC;
    
    // See if a key was provided
       if (null == bytesKey)
       {
       encKey = des.Key;
       }
       else
       {
       des.Key = bytesKey;
       encKey = des.Key;
       }
       // See if the client provided an initialization vector
       if (null == initVec)
       { // Have the algorithm create one
       initVec = des.IV;
       }
       else
       { //No, give it to the algorithm
       des.IV = initVec;
       }
       return des.CreateEncryptor();
       }
       case EncryptionAlgorithm.TripleDes:
       {
       TripleDES des3 = new TripleDESCryptoServiceProvider();
       des3.Mode = CipherMode.CBC;
       // See if a key was provided
       if (null == bytesKey)
       {
       encKey = des3.Key;
       }
       else
       {
       des3.Key = bytesKey;
       encKey = des3.Key;
       }
       // See if the client provided an IV
       if (null == initVec)
       { //Yes, have the alg create one
       initVec = des3.IV;
       }
       else
       { //No, give it to the alg.
       des3.IV = initVec;
       }
       return des3.CreateEncryptor();
       }
       case EncryptionAlgorithm.Rc2:
       {
       RC2 rc2 = new RC2CryptoServiceProvider();
       rc2.Mode = CipherMode.CBC;
       // Test to see if a key was provided
       if (null == bytesKey)
       {
       encKey = rc2.Key;
       }
       else
       {
       rc2.Key = bytesKey;
       encKey = rc2.Key;
       }
       // See if the client provided an IV
       if (null == initVec)
       { //Yes, have the alg create one
       initVec = rc2.IV;
       }
       else
       { //No, give it to the alg.
       rc2.IV = initVec;
       }
       return rc2.CreateEncryptor();
       }
       case EncryptionAlgorithm.Rijndael:
       {
       Rijndael rijndael = new RijndaelManaged();
       rijndael.Mode = CipherMode.CBC;
       // Test to see if a key was provided
       if(null == bytesKey)
       {
       encKey = rijndael.Key;
       }
       else
       {
       rijndael.Key = bytesKey;
       encKey = rijndael.Key;
       }
       // See if the client provided an IV
       if(null == initVec)
       { //Yes, have the alg create one
       initVec = rijndael.IV;
       }
       else
       { //No, give it to the alg.
       rijndael.IV = initVec;
       }
       return rijndael.CreateEncryptor();
       } 
       default:
       {
       throw new CryptographicException("Algorithm ID '" + algorithmID +    
       "' not supported.");
       }
       }
       }
    
  10. Agregue a la clase las siguientes propiedades.

    internal byte[] IV
       {
       get{return initVec;}
       set{initVec = value;}
       }
       internal byte[] Key
       {
       get{return encKey;}
       }
    
  11. Agregue al proyecto una nueva clase con el nombre DecryptTransformer.

  12. Agregue la siguiente instrucción using al principio del archivo DecryptTransformer.cs.

    using System.Security.Cryptography;
    
  13. Cambie el ámbito de la clase de public a internal.

  14. Reemplace el constructor predeterminado por el siguiente constructor.

    internal DecryptTransformer(EncryptionAlgorithm deCryptId)
       {
       algorithmID = deCryptId;
       }
    
  15. Agregue a la clase las siguientes variables privadas.

    private EncryptionAlgorithm algorithmID;
       private byte[] initVec;
    
  16. Agregue a la clase el método siguiente.

    internal ICryptoTransform GetCryptoServiceProvider(byte[] bytesKey)
       {
       // Pick the provider.
       switch (algorithmID)
       {
       case EncryptionAlgorithm.Des:
       {
       DES des = new DESCryptoServiceProvider();
       des.Mode = CipherMode.CBC;
       des.Key = bytesKey;
       des.IV = initVec;
       return des.CreateDecryptor();
       }
       case EncryptionAlgorithm.TripleDes:
       {
       TripleDES des3 = new TripleDESCryptoServiceProvider();
       des3.Mode = CipherMode.CBC;
       return des3.CreateDecryptor(bytesKey, initVec);
       }
       case EncryptionAlgorithm.Rc2:
       {
       RC2 rc2 = new RC2CryptoServiceProvider();
       rc2.Mode = CipherMode.CBC;
       return rc2.CreateDecryptor(bytesKey, initVec);
       }
       case EncryptionAlgorithm.Rijndael:
       {
       Rijndael rijndael = new RijndaelManaged();
       rijndael.Mode = CipherMode.CBC;
       return rijndael.CreateDecryptor(bytesKey, initVec);
       } 
       default:
       {
       throw new CryptographicException("Algorithm ID '" + algorithmID +    
       "' not supported.");
       }
       }
       } //end GetCryptoServiceProvider
    
  17. Agregue a la clase la siguiente propiedad.

    internal byte[] IV
       {
       set{initVec = value;}
       }
    
  18. Agregue al proyecto una nueva clase con el nombre Encryptor.

  19. Agregue las siguientes instrucciones using al principio del archivo Encryptor.cs.

    using System.Security.Cryptography;
       using System.IO;
    
  20. Reemplace el constructor predeterminado por el siguiente constructor.

    public Encryptor(EncryptionAlgorithm algId)
       {
       transformer = new EncryptTransformer(algId);
       }
    
  21. Agregue a la clase las siguientes variables miembro privadas.

    private EncryptTransformer transformer;
       private byte[] initVec;
       private byte[] encKey;
    
  22. Agregue a la clase el siguiente método Encrypt.

    public byte[] Encrypt(byte[] bytesData, byte[] bytesKey)
       {
       //Set up the stream that will hold the encrypted data.
       MemoryStream memStreamEncryptedData = new MemoryStream();
    
    transformer.IV = initVec;
       ICryptoTransform transform = transformer.GetCryptoServiceProvider(bytesKey);
       CryptoStream encStream = new CryptoStream(memStreamEncryptedData, 
       transform, 
       CryptoStreamMode.Write);
       try
       {
       //Encrypt the data, write it to the memory stream.
       encStream.Write(bytesData, 0, bytesData.Length);
       }
       catch(Exception ex)
       {
       throw new Exception("Error while writing encrypted data to the stream:    \n" 
       + ex.Message);
       }
       //Set the IV and key for the client to retrieve
       encKey = transformer.Key;
       initVec = transformer.IV;
       encStream.FlushFinalBlock();
       encStream.Close();
    
    //Send the data back.
       return memStreamEncryptedData.ToArray();
       }//end Encrypt
    
  23. Agregue a la clase las siguientes propiedades.

    public byte[] IV
       {
       get{return initVec;}
       set{initVec = value;}
       }
    
    public byte[] Key
       {
       get{return encKey;}
       }
    
  24. Agregue al proyecto una nueva clase con el nombre Decryptor.

  25. Agregue las siguientes instrucciones using al principio del archivo Decryptor.cs.

    using System.Security.Cryptography;
       using System.IO;
    
  26. Reemplace el constructor predeterminado por el siguiente constructor.

    public Decryptor(EncryptionAlgorithm algId)
       {
       transformer = new DecryptTransformer(algId);
       }
    
  27. Agregue a la clase las siguientes variables miembro privadas.

    private DecryptTransformer transformer;
       private byte[] initVec;
    
  28. Agregue a la clase el siguiente método Decrypt.

    public byte[] Decrypt(byte[] bytesData, byte[] bytesKey)
       {
       //Set up the memory stream for the decrypted data.
       MemoryStream memStreamDecryptedData = new MemoryStream();
    
    //Pass in the initialization vector.
       transformer.IV = initVec;
       ICryptoTransform transform = transformer.GetCryptoServiceProvider(bytesKey);
       CryptoStream decStream = new CryptoStream(memStreamDecryptedData, 
       transform, 
       CryptoStreamMode.Write);
       try
       {
       decStream.Write(bytesData, 0, bytesData.Length);
       }
       catch(Exception ex)
       {
       throw new Exception("Error while writing encrypted data to the stream:    \n" 
       + ex.Message);
       }
       decStream.FlushFinalBlock();
       decStream.Close();
       // Send the data back.
       return memStreamDecryptedData.ToArray();
       } //end Decrypt
    
  29. Agregue a la clase la siguiente propiedad.

    public byte[] IV
       {
       set{initVec = value;}
       }
    
  30. En el menú Generar, haga clic en Generar solución.

Crear una aplicación de prueba de consola

En este procedimiento se crea una sencilla aplicación de prueba de consola para probar la funcionalidad de cifrado y descifrado.

Para crear una aplicación de prueba de consola

  • Agregue a la solución actual una nueva aplicación de consola de C# con el nombre EncryptionTester.

  • En el Explorador de soluciones, haga clic con el botón secundario del mouse (ratón) en el proyecto EncryptionTester y, a continuación, haga clic en Establecer como proyecto de inicio.

  • Utilice el Explorador de soluciones para cambiar el nombre del archivo class1.cs por EncryptionTest.cs.

  • En el archivo EncryptionTest.cs, cambie el nombre de Class1 por EncryptionTest.

  • Agregue una referencia de proyecto al proyecto Encryption.

  • Agregue las siguientes instrucciones using al principio del archivo EncryptionTest.cs.

    using System.Text;
       using Encryption;
    
  • Agregue el siguiente código al método Main.

    // Set the required algorithm
       EncryptionAlgorithm algorithm = EncryptionAlgorithm.Des;
    
    // Init variables.
       byte[] IV = null;
       byte[] cipherText = null;
       byte[] key = null;
    
    try
       { //Try to encrypt.
       //Create the encryptor.
       Encryptor enc = new Encryptor(EncryptionAlgorithm.Des);
       byte[] plainText = Encoding.ASCII.GetBytes("Test String");
    
    if ((EncryptionAlgorithm.TripleDes == algorithm) || 
       (EncryptionAlgorithm.Rijndael == algorithm))
       { //3Des only work with a 16 or 24 byte key.
       key = Encoding.ASCII.GetBytes("password12345678");
       if (EncryptionAlgorithm.Rijndael == algorithm)
       { // Must be 16 bytes for Rijndael.
       IV = Encoding.ASCII.GetBytes("init vec is big.");
       }
       else
       {
       IV = Encoding.ASCII.GetBytes("init vec");
       }
       }
       else
       { //Des only works with an 8 byte key. The others uses variable length keys.
       //Set the key to null to have a new one generated.
       key = Encoding.ASCII.GetBytes("password");
       IV = Encoding.ASCII.GetBytes("init vec");
       }
       // Uncomment the next lines to have the key or IV generated for you.
       // key = null;
       // IV = null;
    
    enc.IV = IV;
    
    // Perform the encryption.
       cipherText = enc.Encrypt(plainText, key);
       // Retrieve the intialization vector and key. You will need it 
       // for decryption.
       IV = enc.IV;
       key = enc.Key;
    
    // Look at your cipher text and initialization vector.
       Console.WriteLine(" Cipher text: " + 
       Convert.ToBase64String(cipherText));
       Console.WriteLine("Initialization vector: " + Convert.ToBase64String(IV));
       Console.WriteLine(" Key: " + Convert.ToBase64String(key));
       }
       catch(Exception ex)
       {
       Console.WriteLine("Exception encrypting. " + ex.Message);
       return;
       }
       try
       { //Try to encrypt.
       //Set up your decryption, give it the algorithm and initialization vector.
       Decryptor dec = new Decryptor(algorithm);
       dec.IV = IV;
       // Go ahead and decrypt.
       byte[] plainText = dec.Decrypt(cipherText, key);
       // Look at your plain text.
       Console.WriteLine(" Plain text: " + 
       Encoding.ASCII.GetString(plainText));
       }
       catch(Exception ex)
       {
       Console.WriteLine("Exception decrypting. " + ex.Message);
       return;
       }
    
  • En el menú Generar, haga clic en Generar solución.

  • Ejecute la aplicación de prueba para comprobar el funcionamiento de las clases Encryptor y Decryptor.

Referencias

Para obtener más información, consulte "Cómo: Almacenar cadenas de conexión cifradas en el Registro" en la sección Referencia de esta guía.

Mostrar: