Este post es una guía paso a paso de cómo crear un proyecto ASP.NET MVC funcional, el cual nos permitirá encriptar y desencriptar de un archivo.

Lo primero de todo es abrir Visual Studios ycrear un nuevo proyecto.

1.nuevo proyecto
2.Tipo

Seleccionamos Vacío (Empty) y MVC.

3.Mvc Empty

El Modelo

Una vez creado nuestro proyecto, sobre la carpeta Models, añadiremos una clase, la cual va ha ser la encargada de cifrar y descifrar los archivos. En mi caso he llamado a esta clase “Crypt”.

4.Agrega clase en model (Crypt)
5.tipo de clase

Una vez tenemos la clase creada, deberemos añadir los recursos que vamos a utilizar.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web;

Añadiremos los métodos que nos permiten codificar las claves (convertir a byte[]) para que tengan el formato establecido por la codificación Rijndael.

    public static byte[] EncodingPrivateKey(String privada)
        {
            byte[] key = UTF8Encoding.UTF8.GetBytes(privada);
            int keySize = 32;
            Array.Resize(ref key, keySize);
            return key;
        }

     public static byte[] EncodingPublicKey(String publica)
        {
            byte[] iv = UTF8Encoding.UTF8.GetBytes(publica);
            int ivSize = 16;
            Array.Resize(ref iv, ivSize);
            return iv;
        }

Ahora crearemos los métodos que se encargarán de encriptar y desencriptar los ficheros que se crearán.

El método “EncryptToFile” contendrá cuatro parámetros:

-El texto que guardaremos en el fichero(“plainMessage”).

-La ruta mapeada más el nombre del archivo a generar(“filename”).

-La clave privada convertida en byte[](“key”).

-La clave pública convertida en byte[](“IV”).

Será un método void (No devuelve nada).

public static void encryptToFile(String plainMessage, String filename, byte[] Key, byte[] IV){}

A continuación, crearemos el flujo del archivo a generar.

 FileStream fileStream = File.Open(filename,FileMode.OpenOrCreate);

También añadiremos el flujo de la clase Rijndael.

Rijndael RijndaelAlg = Rijndael.Create();

Ahora el CryptoStream, que es el flujo de datos cifrados.

-Nota Importante-

Ten en cuenta que estamos escribiendo en un archivo, por lo que deeremos usar CryptoStreamMode.Write, más adelante veremos que con Readpodremos desencriptar dicho archivo.

CryptoStream cryptoStream = new CryptoStream(fileStream,                                                   
                            RijndaelAlg.CreateEncryptor(Key, IV),
                                         CryptoStreamMode.Write);

También añadiremos el flujo de escritura StreamWriter.

 StreamWriter streamWriter = new StreamWriter(cryptoStream);

Por último, ciframos el contenido del archivo y cerramos todos los flujos creados.

streamWriter.WriteLine(plainMessage);

streamWriter.Close();
cryptoStream.Close();
fileStream.Close();

El método completo quedaría así:

public static void encryptToFile(String plainMessage, String filename, 
          byte[] Key, byte[] IV)
        {
            // Crear un flujo para el archivo a generarse
            FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate);

            // Crear una instancia del algoritmo Rijndael
            Rijndael RijndaelAlg = Rijndael.Create();

            // Crear un flujo de cifrado basado en el flujo de los datos
            CryptoStream cryptoStream = new CryptoStream(fileStream,
                                                         RijndaelAlg.CreateEncryptor(Key, IV),
                                                         CryptoStreamMode.Write);

            // Crear un flujo de escritura basado en el flujo de cifrado
            StreamWriter streamWriter = new StreamWriter(cryptoStream);

            // Cifrar el mensaje a través del flujo de escritura
            streamWriter.WriteLine(plainMessage);

            // Cerrar los flujos utilizados
            streamWriter.Close();
            cryptoStream.Close();
            fileStream.Close();
        }

Este método está listo para su uso, pero ahora vamos a crear el método de descifrado(“DecryptFromFile”), que devolverá un String.

Es muy parecido, salvo qué, en vez de escribir, vamos a tener que leer el archivo.

Esta vez solo recibirá los parámedros de:

-Nombre del archivo (“filename”).

-La clave privada convertida en byte[](“key”).

-La clave pública convertida en byte[](“IV”).

public static string decryptFromFile(String filename, byte[] Key, byte[] IV){}

Abrimos los flujos FileStream y Rijndael, exactamente igual que antes.

FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate);

Rijndael RijndaelAlg = Rijndael.Create();

Añadimos el flujo de CryptoStream, salvo que esta vez con el CyptoStreamMode.Read.

CryptoStream cryptoStream = new CryptoStream(fileStream,                                                       
                            RijndaelAlg.CreateDecryptor(Key, IV),
                                          CryptoStreamMode.Read);

Ahora debemos abrir el flujo StreamReader.

 StreamReader streamReader = new StreamReader(cryptoStream);

Por último, al igual que antes; Deberemos desencriptar el archivo y cerrar todos los flujos usados.

Este método tiene que devolver un String, muy importante no olividar el return.

string plainMessage = streamReader.ReadLine();

streamReader.Close();
cryptoStream.Close();
fileStream.Close();

return plainMessage;

El método completo quedaría así:

public static string decryptFromFile(String filename, byte[] Key, byte[] IV)
        {
            // Crear un flujo para el archivo a generarse
            FileStream fileStream = File.Open(filename, FileMode.OpenOrCreate);

            // Crear una instancia del algoritmo Rijndael
            Rijndael RijndaelAlg = Rijndael.Create();

            // Crear un flujo de cifrado basado en el flujo de los datos
            CryptoStream cryptoStream = new CryptoStream(fileStream,
                                                         RijndaelAlg.CreateDecryptor(Key, IV),
                                                         CryptoStreamMode.Read);

            // Crear un flujo de lectura basado en el flujo de cifrado
            StreamReader streamReader = new StreamReader(cryptoStream);

            // Descifrar el mensaje a través del flujo de lectura
            string plainMessage = streamReader.ReadLine();

            // Cerrar los flujos utilizados
            streamReader.Close();
            cryptoStream.Close();
            fileStream.Close();

            return plainMessage;
        }

Con esto ya hemos terminado con el archivo “Crypt”.

El Controlador

Es hora de añadir un controlador en la carpeta Controllers, el cual será el encargado de devolver las vistas y el que recibirá la información necesaria mediante el método Post.

20.Añadir controlador

Seleccionamos la primera opción MVC 5 Controller – Empty

21.controlador vacio

En mi caso he llamado al controlador “CrypticController”.

22.nombre controlador

Una vez añadido, deberemos cambiar el nombre al método Index (no es necesario) por “CifrarArchivo”.

 public class CrypticController : Controller
    {
        // GET: CifrarArchivo
        public ActionResult CifrarArchivo()
        {
            return View();
        }
    }

Añadimos el método Post, que es el que realmente va a obtener los datos de la vista.

// POST: CifrarArchivo
   [HttpPost]
   public ActionResult CifrarArchivo(String texto, String publica, 
           String privada, String archivo){}

Muy importante que tenga el mismo nombre que el Get.

Los parámetros que contiene serán <input> de la vista cuyo name serán los mismos que los que estamos viendo.

Creamos una carpeta al mismo nivel que el proyecto llamada “Files”.

25.creamos carpeta Files

En el método Post de “CifrarAchivo”, añadiremos el siguiente código para mapear la carpeta anteriormente creada.

String rute = Server.MapPath("~/Files");

String path = Path.Combine(rute, archivo + ".txt");

Necesitaremos incluir los siguiente using:

using EjemploCifrarDescifrarArchivo.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;

Invocamos el método “EncryptToFile” generado en la case “Crypt”.

Hay que tener en cuenta que las claves las estamos recogiendo en formato String, por lo que habrá que usar los métodos creados con anterioridad para pasarlos a byte[].

Tiene que quedar así:

// POST: CifrarArchivo
   [HttpPost]
   public ActionResult CifrarArchivo(String texto, String publica, 
          String privada, String archivo)
        {
            //Mapea la carpeta especificada.
            String rute = Server.MapPath("~/Files");

            //Juntamos la carpeta mapeada + el nombre del archivo + 
            //.txt
            String path = Path.Combine(rute, archivo + ".txt");

            //Guardamos la clave Pública en una sesión para no tener 
            //que volver a preguntarla.
            Session["Publica"] = publica;

            //Llamamos a los metodos de Crypt para poder realizar el 
            //cifrado del archivo.
            Crypt.encryptToFile(texto, path, 
                       Crypt.EncodingPrivateKey(privada), 
                       Crypt.EncodingPublicKey(publica));

            //Redireccionamos a la View que permite descifrar el 
            //archivo.
            return RedirectToAction("DescifrarArchivo", "Cryptic");
        }

-Nota Importante-

En este ejemplo estoy usando Session para guardar la clave pública, pero esta clave debería ir en una base de datos asociada a un nombre de archivo, para que la clave no se pierda y siempre se pueda consultar, pero para no dificultar el ejemplo, he decidido utilizar Session.

Por lo tanto, si cierra el navegado cuando esté ejecutando el programa, el archivo al no tener una clave pública ejecutará una excepción.

También se han omitido las validaciones para poder centrar este Tutorial a su finalidad final: Cifrar y descifrar un archivo con Asp.Net MVC.

La Vista (Cifrar)

Añadimos la View de la siguiente forma. (click derecho sobre el nombre del método)

29.crear vista de cifrar

Dejamos todo por defecto.

30.confirmamos view

Una vez Creada la vista introduciremos el siguiente código.


@{
    ViewBag.Title = "Cifrar";
}

<h2>Crear y Cifrar un Archivo</h2>
@using (Html.BeginForm("CifrarArchivo", "Cryptic", FormMethod.Post))
{
    <div class="form-group">
        <label class="control-label">Texto a cifrar</label>
        <textarea name="texto" class="form-control"></textarea>
    </div>
    <div class="form-group">
        <label class="control-label">Clave Pública</label>
        <input type="password" name="publica" class="form-control" />
    </div>
    <div class="form-group">
        <label class="control-label">Clave Privada</label>
        <input type="password" name="privada" class="form-control" />
    </div>
    <div class="form-group">
        <label class="control-label">Nombre Arhivo</label>
        <input type="text" name="archivo" class="form-control" />
    </div>
    <div class="form-group">
        <button type="submit">Cifrar</button>
    </div>

}

Creamos los métodos Get y Post de “DescifrarArchivo”, muy parecidos a los métodos anteriores.

// GET: DescifrarArchivo
        public ActionResult DescifrarArchivo()
        {
            return View();
        }

// POST: DescifrarArchivo
   [HttpPost]
   public ActionResult DescifrarArchivo(String privada, String archivo)
        {
            String rute = Server.MapPath("~/Files");
            String path = Path.Combine(rute, archivo + ".txt");
            ViewBag.Text = Crypt.decryptFromFile(path,
              Crypt.EncodingPrivateKey(privada),
              Crypt.EncodingPublicKey(Session["Publica"].ToString()));
            return View();
        }

Esta vez solo recibirá los parámetros del nombre del archivo a descifrar y su clave privada.

Como el método “DecryptFromFile” devuelve un String, podemos guardarlo en un ViewBag para mostrar la información en un <textarea> por ejemplo.

(Recuerda que la clave pública está almacenada en Session.)

La Vista (Descifrar)

Añadimos la vista como antes.

33.Vista

Incluimos el HTML en la vista que hemos creado.


@{
    ViewBag.Title = "DescifrarArchivo";
}

<h2>DescifrarArchivo</h2>
@using (Html.BeginForm("DescifrarArchivo", "Cryptic", FormMethod.Post, new { @enctype = "multipart/form-data " }))
{
    <div class="form-group">
        <label class="control-label">Clave Privada</label>
        <input type="password" name="privada" class="form-control" />
    </div>
    <div class="form-group">
        <label class="control-label">Nombre Arhivo</label>
        <input type="text" name="archivo" class="form-control" />
    </div>
    <div class="form-group">
        <button type="submit">DesCifrar</button>
    </div>
}
<div class="form-group">
    <label class="control-label">Texto Descifrado</label>
    <textarea name="texto" class="formcontrol">@ViewBag.Text</textarea>
</div>

Con esto abríamos terminado todo lo necesario para el correcto funcionamiento del programa.


Puntos Importantes

Os dejo una lista de los puntos importantes que hay que tener en cuenta a la hora de querer desarrollar correctamente la aplicación:

  • Entender el funcionamiento de la clase Rijndael.
  • Hay que controlar las excepciones, ya que si te equivocas en la clave privada a la hora de intentar desencriptar el archivo, Rijndael lanzará una excepción .Esto se puede solucionar añadiendo un TryCatch() en el momento en el que se llama a la clase.
  • Si cerramos el navegador perdemos la clave pública. Esto se puede solucionar guardando la clave en una base de datos, ya que es la pública y está diseñada para ello.

Les dejo la dirección de donde está subido el proyecto para que puedan probarlo.

También les dejo un vídeo complementario en el que les muestro el funcionamiento.

No olviden dejar algún comentario si tienen cualquier tipo de dudas.

Muchas gracias por seguir este tutorial.


Autor/a: Daniel Pizarro Cuervo

Curso: Microsoft MCSA Web Applications + Microsoft MCSD App Builder + Xamarin

Centro: Tajamar

Año académico: 2018-2019

Enlace del Proyecto: Github.

Enlace del Video: Video

Leave a Comment

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.