En este artículo se describe cómo utilizar las clases de
cifrado que proporciona Microsoft .NET Framework para cifrar un archivo de
texto en un estado ilegible y descifrar después ese archivo para devolverlo a
su estado original.
El espacio de nombres System.Security.Cryptographic de Microsoft .NET Framework proporciona diversas herramientas
para ayudarle con el cifrado y el descifrado. La clase CryptoStream es una de las muchas clases que se proporcionan. La clase CryptoStream está diseñada para cifrar o descifrar el contenido a medida que
se transmite en secuencias a un archivo.
Haga clic en Visual C# bajo
Proyectos y, a continuación, haga clic en Aplicación
de consola bajo Plantillas. Visual C# .NET crea
automáticamente una clase Static junto con un procedimiento Main() vacío.
Utilice la instrucción using (como se indica en el código de ejemplo siguiente) en los
espacios de nombres siguientes:
System
System.Security
System.Security.Cryptography
System.Text
System.IO
de manera que no se le pida que califique las declaraciones
de estos espacios de nombres más tarde en el código. Debe utilizar estas
instrucciones antes que cualquier otra declaración.
using System; using System.IO; using System.Security; using System.Security.Cryptography; using System.Runtime.InteropServices; using System.Text;
Genere una clave secreta para cifrar y descifrar los datos.
DESCryptoServiceProvider se basa en un algoritmo de cifrado simétrico. El cifrado
simétrico requiere una clave y un vector de inicialización (IV) para cifrar los
datos. Para poder descifrar los datos, debe tener la misma clave y el mismo IV.
También debe utilizar el mismo algoritmo de cifrado. Puede generar las claves
mediante cualquiera de los métodos siguientes.
Método 1 Puede solicitar una contraseña al usuario. Después, utilice la
contraseña como la clave y el IV.
Método 2 Cuando cree una nueva instancia de las clases de cifrado
simétrico, se crearán automáticamente una clave y un IV nuevos para la sesión.
Utilice la clave y el IV generados por las clases de cifrado simétrico
administradas para cifrar y descifrar el archivo.
Para obtener más
información acerca de cómo generar y distribuir claves, consulte la
documentación del SDK de Microsoft .NET Framework o visite el siguiente sitio
Web de Microsoft Developer Network (MSDN):
Agregue la función siguiente para generar una nueva clave
para una sesión (como se indicó en el método 2 del paso 4):
// Llamar a esta función para quitar la clave de la memoria después de su uso por seguridad. [System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")] public static extern bool ZeroMemory(ref string Destination, int Length);
// Función para generar una clave de 64 bits. static string GenerateKey() { // Crear una instancia del algoritmo simétrico. La clave y el IV se generan automáticamente. DESCryptoServiceProvider desCrypto =(DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Utilizar la clave generada automáticamente para el cifrado. return ASCIIEncoding.ASCII.GetString(desCrypto.Key); }
Cree un método en su clase denominado EncryptFile. La clase EncryptFile debe tener los tres parámetros siguientes:
sInputFilename
sOutputFilename
sKey (La clave secreta que se utiliza para cifrar y descifrar el
archivo.)
En el procedimiento EncryptFile, cree un objeto FileStream de entrada y un objeto FileStream de salida. Estos objetos se pueden leer desde los archivos de
destino y escribir en los mismos.
FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
Declare una instancia de la clase DESCryptoServiceProvider. Esto representa el cifrado real y la tecnología de descifrado
real que se utilizan en los archivos. En este momento puede crear un proveedor
diferente si prefiere utilizar RSAsecutiry u otra técnica de cifrado.
DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
Se debe proporcionar al proveedor de cifrado su clave
secreta como una matriz de bytes. El espacio de nombres System.Text proporciona una función denominada GetBytes(). Como parte de sus características de codificación, la función GetBytes() toma una cadena y devuelve una matriz de bytes. El tamaño de la
clave es diferente para cada técnica de cifrado. Por ejemplo, el Estándar de
cifrado de datos (DES) toma una clave de 64 bits que es igual a 8 bytes o a 8
caracteres.
Si no proporciona ninguna clave, el proveedor genera una
aleatoriamente. Esto cifra correctamente el archivo, pero no hay ninguna manera
de descifrarlo. Tenga en cuenta que también debe proporcionar el vector de
inicialización (IV). Este valor se utiliza como parte del cifrado. Al igual que
la clave, el IV se genera aleatoriamente si no proporciona el valor. Puesto que
los valores deben ser los mismos para el cifrado y el descifrado, no debe
permitir la generación aleatoria de estos valores.
Cree una instancia de la clase CryptoStream utilizando el proveedor de cifrado para obtener un objeto de
cifrado (CreateEncryptor) y el objeto FileStream de salida existente como parte del constructor.
Lea el archivo de entrada y, a continuación, escriba en el
archivo de salida. Recorra el objeto CryptoStream donde se cifra el archivo utilizando la clave que proporcionó.
Cree un método y asígnele el nombre
DecryptFile. El proceso de descifrado es similar al
proceso de cifrado; sin embargo, el procedimiento DecryptFile tiene dos diferencias clave con respecto al procedimiento EncryptFile.
CreateDecryptor se utiliza en lugar de CreateEncryptor para crear el objeto CryptoStream, que especifica cómo se puede utilizar el objeto.
Cuando el texto descifrado se escribe en el archivo de
destino, el objeto CryptoStream es ahora la secuencia de origen en lugar de la secuencia de
destino.
static void DecryptFile(string sInputFilename, string sOutputFilename, string sKey) { DESCryptoServiceProvider DES = new DESCryptoServiceProvider(); //Se necesita una clave de 64 bits y un IV para este proveedor. //Establecer la clave secreta para el algoritmo DES. DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey); //Establecer el vector de inicialización. DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Crear una secuencia de archivo para volver a leer el archivo cifrado. FileStream fsread = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read); //Crear un descriptor de DES desde la instancia de DES. ICryptoTransform desdecrypt = DES.CreateDecryptor(); //Crear una secuencia de cifrado para leer y //realizar una transformación de cifrado DES en los bytes de entrada. CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read); //Imprimir el contenido del archivo descifrado. StreamWriter fsDecrypted = new StreamWriter(sOutputFilename); fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd()); fsDecrypted.Flush(); fsDecrypted.Close(); }
Agregue las líneas siguientes al procedimiento Main() para llamar a EncryptFile y DecryptFile:
static void Main() { // Debe ser 64 bits, 8 bytes. // Distribuir esta clave al usuario que descifrará este archivo. string sSecretKey;
// Obtener la clave para que el archivo se cifre. sSecretKey = GenerateKey();
// Para mayor seguridad, fijar la clave. GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );
// Cifrar el archivo. EncryptFile(@"C:\MyData.txt", @"C:\Encrypted.txt", sSecretKey);
// Descifrar el archivo. DecryptFile(@"C:\Encrypted.txt", @"C:\Decrypted.txt", sSecretKey);
// Quitar la clave de la memoria. ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2); gch.Free(); }
Guarde el archivo. Ejecute la aplicación. Asegúrese de que
la ruta de acceso que se utiliza para el nombre del archivo de entrada señala a
un archivo existente.
Probar el procedimiento
Pruebe este código con un archivo de texto (.txt) para confirmar
que el código cifró y descifró el archivo correctamente. Asegúrese de que
descifra el archivo en un nuevo archivo (como en el procedimiento Main() de este artículo) en lugar de hacerlo en el archivo original.
Examine el archivo descifrado y, a continuación, compárelo con el archivo
original.
using System; using System.IO; using System.Security; using System.Security.Cryptography; using System.Runtime.InteropServices; using System.Text;
namespace CSEncryptDecrypt { class Class1 { // Llamar a esta función para quitar la clave de la memoria después de su uso por seguridad [System.Runtime.InteropServices.DllImport("KERNEL32.DLL", EntryPoint="RtlZeroMemory")] public static extern bool ZeroMemory(IntPtr Destination, int Length);
// Función para generar una clave de 64 bits. static string GenerateKey() { // Crear una instancia del algoritmo simétrico. La clave y el IV se generan automáticamente. DESCryptoServiceProvider desCrypto =(DESCryptoServiceProvider)DESCryptoServiceProvider.Create();
// Utilizar la clave generada automáticamente para el cifrado. return ASCIIEncoding.ASCII.GetString(desCrypto.Key); }
static void EncryptFile(string sInputFilename, string sOutputFilename, string sKey) { FileStream fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
FileStream fsEncrypted = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write); DESCryptoServiceProvider DES = new DESCryptoServiceProvider(); DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey); DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey); ICryptoTransform desencrypt = DES.CreateEncryptor(); CryptoStream cryptostream = new CryptoStream(fsEncrypted, desencrypt, CryptoStreamMode.Write);
byte[] bytearrayinput = new byte[fsInput.Length]; fsInput.Read(bytearrayinput, 0, bytearrayinput.Length); cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length); cryptostream.Close(); fsInput.Close(); fsEncrypted.Close(); }
static void DecryptFile(string sInputFilename, string sOutputFilename, string sKey) { DESCryptoServiceProvider DES = new DESCryptoServiceProvider(); //Se necesita una clave de 64 bits y un IV para este proveedor. //Establecer la clave secreta para el algoritmo DES. DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey); //Establecer el vector de inicialización. DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
//Crear una secuencia de archivo para volver a leer el archivo cifrado. FileStream fsread = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read); //Crear un descriptor de DES desde la instancia de DES. ICryptoTransform desdecrypt = DES.CreateDecryptor(); //Crear una secuencia de cifrado para leer y //realizar una transformación de cifrado DES en los bytes de entrada. CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read); //Imprimir el contenido del archivo descifrado. StreamWriter fsDecrypted = new StreamWriter(sOutputFilename); fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd()); fsDecrypted.Flush(); fsDecrypted.Close(); }
static void Main() { // Debe ser 64 bits, 8 bytes. // Distribuir esta clave al usuario que descifrará este archivo. string sSecretKey;
// Obtener la clave para que el archivo se cifre. sSecretKey = GenerateKey();
// Para mayor seguridad, fijar la clave. GCHandle gch = GCHandle.Alloc( sSecretKey,GCHandleType.Pinned );
// Cifrar el archivo. EncryptFile(@"C:\MyData.txt", @"C:\Encrypted.txt", sSecretKey);
// Descifrar el archivo. DecryptFile(@"C:\Encrypted.txt", @"C:\Decrypted.txt", sSecretKey);
// Quitar la clave de la memoria. ZeroMemory(gch.AddrOfPinnedObject(), sSecretKey.Length * 2); gch.Free(); } } }