Colabora
 

Datos encriptados con C#

Utilizando el algoritmo SHA

 

Fecha: 06/Dic/2011 (25/Noviembre/2011)
Autor: Rolando Zapata Maraví

http://rolanzm.wordpress.com

 


Introducción

En muchas ocasiones necesitamos almacenar datos sensibles que requieren cierto nivel de protección, para ello podemos utilizar los algoritmos de encriptación estándares que existen en el mundo de la informática. Uno de ellos es el algoritmo SHA (que quiere decir Secure Hash Algorithm o en español Algoritmo de Hash Seguro). Existen distintas versiones del algoritmo SHA, tales como el SHA-0, SHA-1, SHA-2 y algunas otras que tienen como base éste último; te invito a revisar un poco más de teoría sobre este algoritmo para comprender mucho mejor cada una de sus variantes, examinar sus ventajas, modo de funcionamiento e incluso algunas de sus vulnerabilidades que se publican en la red.

El caso que abordaremos será el de almacenar números de tarjeta con sus respectivas claves, éste último dato lo guardaré encriptado en la base de datos utilizando el algoritmo SHA. Cabe destacar que esta es una de las tantas técnicas que existen para almacenar datos encriptados; ya que también podemos encriptar a nivel de base de datos (dependiento del Sistema Gestor de Base de Datos que estemos utilizando).

Creación de la base de datos

Lo primero que haremos será crear una base de datos sencilla que nos permita almacenar información de números de tarjeta con sus respectivas claves. Para ello aperturamos el SQL Server 2008 y en una nueva ventana de consulta ingresamos el siguiente código T-SQL.

-- Creando la base de datos
use master
create database creditos
go
-- Creando la tabla tarjetas
use creditos
create table tblTarjeta
(
numero varchar(20) not null,
clave varchar(200) not null
)
go

Luego vamos a crear un procedimiento almacenado que permita realizar la inserción respectiva. Recordemos que la mejor manera de realizar operaciones sobre una base de datos es utilizando procedimientos almacenados.

--Creando un procedimiento almacenado que permita registrar
use creditos
go
create procedure usp_insertar_tarjeta
@numero varchar(20),
@clave varchar(200)
as
insert into tblTarjeta values (@numero,@clave )
go

Interfaz gráfica

El lenguaje de programación utilizado en esta demostración es C#, por lo tanto crearemos un proyecto de tipo "Aplicación de Windows Forms" en dicho lenguaje con el siguiente formulario:


Código

A continuación crearemos un módulo con una función estática que nos permita realizar el encriptado respectivo. Para ello, agregamos al proyecto una clase con el nombre clsFunciones y dentro de la misma codificamos una función estática con el nombre encriptar, tal y como se muestra en el siguiente segmento de código:

using System;
using System.Security.Cryptography;

namespace Demo_1_encriptarClaves_1
{
    internal class clsFunciones
    {       
        public static string encriptar(string laCadena)
        {              
                SHA1CryptoServiceProvider elProveedor = new SHA1CryptoServiceProvider();
                byte[] vectoBytes=System.Text.Encoding.UTF8.GetBytes(laCadena );
                byte[] inArray = elProveedor.ComputeHash(vectoBytes);
                elProveedor.Clear();
                return Convert.ToBase64String(inArray);            
        }
    }
}

Ahora crearemos una clase con los campos, propiedades y métodos necesarios pare resolver el problema. En la elaboración de la misma, he tomado las siguientes reglas de validación: El número de la tarjeta y la clave son datos obligatorios, además de que el número de la tarjeta no debe exceder de 20 caracteres y la clave debe contener como mínimo 8 caracteres sin considerar espacios en blanco. Entonces agregamos un clase a nuestro proyecto con el nombre clsTarjeta y codificamos su contenido de acuerdo a las siguientes líneas de código.

Nota: Dentro del método registrar, el nombre del servidor (en el parámetro server) es igual a un .(punto), que quiere decir servidor local y puede ser reemplazado por el nombre de tu PC o nombre del servidor. Considera que debes modificar el nombre del servidor, si utilizas alguna instancia de SQL Server específica (éstos parámetros se establecen de acuerdo al tipo de instalación de SQL Server). Por ejemplo, si trabajas con SQL Server Express, probablemte el nombre del servidor quedaría así: server=.\\sqlexpress (No olvidemos que si quieres colocar un backslash en C# tienes que insertarlo dos veces).

using System.Data.SqlClient;
using System.Data;
using System;
namespace Demo_1_encriptarClaves_1
{
public class clsTarjeta
{ private string _numero;
private string _clave;
public clsTarjeta(string elNumero,string laClave )
{
numero = elNumero;
clave = laClave;
} public string numero
{
get
{
return _numero ;
} set
{
if (value.Trim().Length == 0)
{
throw new ArgumentNullException ("El número de tarjeta no puede quedar vacío.");
}
else if (value.Trim().Length >20)
{
throw new ArgumentOutOfRangeException("El número de tarjeta tiene un formato inválido.");
}
else
{
_numero = value.Trim();
}
}
}
public string clave
{
get
{
return _clave;
}
set
{
if (value.Trim().Length == 0) { throw new ArgumentNullException("La clave no admite espacios en blanco."); } else if (value.Length <8 ) { throw new ArgumentOutOfRangeException("La clave debe contener por lo menos 8 caracteres."); } else { for (byte i = 0; i < value.Length ; i++) { if (value.Substring(i, 1) == " ") throw new Exception("La clave contiene espacios en blanco."); } _clave = value; }
}
} /// <summary>
/// Registra una nueva tarjeta en la base de datos.
/// </summary>
public void registrar()
{
SqlConnection conexion = new SqlConnection("server=.;database = creditos;integrated security=true");
SqlCommand comando = new SqlCommand("usp_insertar_tarjeta", conexion);
comando.CommandType = CommandType.StoredProcedure;
comando.Parameters.AddWithValue("@numero", numero);
comando.Parameters.AddWithValue("@clave", clsFunciones.encriptar(clave));
conexion.Open();
comando.ExecuteNonQuery();
conexion.Close();
conexion.Dispose();
}
}
}

Luego abrimos el formulario creado anteriormente y codificamos el evento click del botón registrar.

        private void btnRegistrar_Click(object sender, EventArgs e)
        {
            try
            {
                clsTarjeta nuevaTarjeta = new clsTarjeta(txtNumeroTarjeta.Text, txtClave.Text);
                nuevaTarjeta.registrar();
            }

            catch (ArgumentNullException error)
            {
                MessageBox.Show("Complete los datos requeridos." + "\n" + error.ParamName, "Demo", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                txtClave.Clear();
                txtNumeroTarjeta.SelectAll();
                txtNumeroTarjeta.Focus();
                return;
            }

            catch (ArgumentOutOfRangeException error)
            {
                MessageBox.Show(error.ParamName , "Demo", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                txtClave.Clear();
                txtNumeroTarjeta.SelectAll();
                txtNumeroTarjeta.Focus();
                return;
            }

            catch (Exception error)
            {
                MessageBox.Show("Ha ocurrido un error." + "\n" +  "Detalle: " + error.Message, "Demo", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                txtClave.Clear();
                txtNumeroTarjeta.SelectAll();
                txtNumeroTarjeta.Focus();
                return;
            }

            MessageBox.Show("Inserción completada.", "Ing. Rolando Zapata Maraví", MessageBoxButtons.OK, MessageBoxIcon.Information);
            txtNumeroTarjeta.Clear();
            txtClave.Clear();
            txtNumeroTarjeta.Focus();
        }

Para evitar que el usuario ingrese otros caracteres que no sean números en el número de la tarjeta, modificamos el evento KeyPress del txtNumeroTarjeta para que se muestre de la siguiente forma:

 
        private void txtNumeroTarjeta_KeyPress(object sender, KeyPressEventArgs e)
        {
            //Validando que se ingresen sólo números.
             if (Char.IsDigit(e.KeyChar))
                e.Handled = false;
             else if (Char.IsControl(e.KeyChar))
                e.Handled = false;
             else if (Char.IsSeparator(e.KeyChar))
                e.Handled = true;
             else
                e.Handled = true;  
        }

Finalmente el código del evento click del botón Cerrar

        private void btnCerrar_Click(object sender, EventArgs e)
        {
            //Terminando la aplicación
            Application.Exit();
        }

Para probar la aplicación, ejecutamos el formulario e ingresamos datos:


Luego de pulsar el botón registrar, la aplicación nos mostrará un mensaje de confirmación de registro o un mensaje de error si hubieran datos inválidos en el formulario (recordemos las reglas de validación que propusimos anteriormente). Una vez completado el proceso de registro satisfactoriamente, ingresamos el siguiente T-SQL en una nueva ventana de consulta de SQL Server:

use creditos
SELECT numero, clave
FROM tblTarjeta

Ejecutamos la consulta anterior y obtenemos el siguiente resultado:


Como podemos apreciar, la clave de acceso ha sido encriptada.

Conclusión

Los datos sensibles a encriptar nunca faltan en las aplicaciones y sistemas de información, por lo tanto debemos de conocer métodos de encriptación estándares que nos permitan brindar seguridad a dichos datos. En el mercado informático encontramos una serie de posibilidades para encriptar, tanto desde la aplicación como desde la base de datos, ésta ha sido una breve demostración que prentende incentivar al lector a investigar sobre las distintas formas de encriptado.

Gracias por su atención y hasta la próxima.


Espacios de nombres adicionales usados en el código de este artículo:

Para la clase clsTarjeta

using System.Data.SqlClient;
using System.Data;
using System;

Para el módulo clsFunciones

using System.Security.Cryptography;
using System;

Para el formulario

using System.Windows.Forms;
using System;

 

 
 


Compromiso del autor del artículo con el sitio del Guille:

Lo comentado en este artículo está probado (y funciona) con la siguiente configuración:

El autor se compromete personalmente de que lo expuesto en este artículo es cierto y lo ha comprobado usando la configuración indicada anteriormente.

En cualquier caso, el Guille no se responsabiliza del contenido de este artículo.

Si encuentras alguna errata o fallo en algún link (enlace), por favor comunícalo usando este link:

Gracias.


Código de ejemplo (comprimido):

 

Fichero con el código de ejemplo: rolanzm_encriptar_datos_con_sha.zip - 18.6 KB

MD5 checksum: D4E56C34DFF6F6D4B9E0950F4F90599D


Ir al índice principal de el Guille