Archivo de agosto 2009


Utilizar certificados digitales desde .NET

Viernes, 21 ago, 2009 @ 09:20 | Por Gustavo Cantero (The Wolf) | .NET, Certificados Digitales, Seguridad

Luego de mis artículos sobre certificados digitales, firma digital y hash sólo me queda escribir el último de esta serie en donde me gustaría mostrar cómo buscar, leer y utilizar estos certificados X.509 desde .NET.

Consultar los repositorios de certificados

Como primer paso vamos a recorrer los certificados que tenemos instalados en nuestra máquina. Para esto debemos utilizar la clase X509Store, la cual nos da la posibilidad de consultar un repositorio de certificados, por ejemplo, el repositorio raíz (Root), el repositorio donde están los certificados de las autoridades certificantes (CertificateAuthority), o el repostorio personal (My). También tenemos que elegir la ubicación del certificado, es decir, si vamos a querer consultar los certificados que están a nivel de máquina o de usuario. Tengan en cuenta que si van a utilizar la clase X509Store desde ASP.NET deben leer los certificados que están a nivel de máquina, ya que el usuario ASP.NET rara vez va a tener algún certificado instalado.

Luego de elegido el repositorio que queremos abrir debemos utilizar el método Open para que consulte al mismo.

Una vez abierto el repositorio, la propiedad Certificates contendrá una colección (basada en la clase X509Certificate2Collection) de los certificados almacenados.

Después de utilizar el repositorio no hay que olvidar de cerrar el mismo con método Close.

A continuación muestro cómo abrir el repositorio personal y escribir en la consola de debug los nombres y firmas digitales (hash) de cada certificado:

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
...
X509Store objStore = new X509Store(StoreName.My, StoreLocation.LocalMachine);
objStore.Open(OpenFlags.ReadOnly);

foreach (X509Certificate2 objCert in objStore.Certificates)
    Debug.Print(objCert.SubjectName.Name + ": " + objCert.Thumbprint);

objStore.Close();

Consultar la información del certificado y sus extensiones

Cada certificado posee una serie de datos (los cuales se describen en el artículo Conceptos de Certificado Digital y Firma Digital y creamos en el artículo Crear certificados de prueba para servidor y cliente). Además de estos datos los certificados poseen extensiones, que definen distintos posibles usos dependiendo de las mismas, y según la extensión poseen distintos datos almacenados. Por ejemplo, en la extensión del tipo “2.5.29.37” (también llamada “Enhanced Key Usage”) se guarda cual va a ser el destino del certificado, por ejemplo para autenticación del cliente.

Estas extensiones están en la colección Extensions del certificado, y para obtener la información almacenada debe castearse según el tipo del mismo. Para saber qué tipo de extensión es la almacenada se puede leer la propiedad Oid, la cual devuelve la clase homónima que representa un identificador de un objeto criptográfico (cryptographic object identifier) y luego, de este objeto, podemos leer la propiedad FriendlyName para obtener el nombre de la extensión.

A continuación hay un código de ejemplo donde se muestra la información de un certificado:

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
using System.Text;
...
X509Certificate2 objCert = ... //Acá tenemos que poner el certificado
StringBuilder objSB = new StringBuilder("Detalle del certificado: \n\n");

//Detalle
objSB.AppendLine("Persona = " + objCert.Subject);
objSB.AppendLine("Emisor = " + objCert.Issuer);
objSB.AppendLine("Válido desde = " + objCert.NotBefore.ToString());
objSB.AppendLine("Válido hasta = " + objCert.NotAfter.ToString());
objSB.AppendLine("Tamaño de la clave = " + objCert.PublicKey.Key.KeySize.ToString());
objSB.AppendLine("Número de serie = " + objCert.SerialNumber);
objSB.AppendLine("Hash = " + objCert.Thumbprint);

//Extensiones
objSB.AppendLine("\nExtensiones:\n");
foreach (X509Extension objExt in objCert.Extensions)
{
    objSB.AppendLine(objExt.Oid.FriendlyName + " (" + objExt.Oid.Value + ')');

    if (objExt.Oid.FriendlyName == "Key Usage")
    {
        X509KeyUsageExtension ext = (X509KeyUsageExtension)objExt;
        objSB.AppendLine("    " + ext.KeyUsages);
    }

    if (objExt.Oid.FriendlyName == "Basic Constraints")
    {
        X509BasicConstraintsExtension ext = (X509BasicConstraintsExtension)objExt;
        objSB.AppendLine("    " + ext.CertificateAuthority);
        objSB.AppendLine("    " + ext.HasPathLengthConstraint);
        objSB.AppendLine("    " + ext.PathLengthConstraint);
    }

    if (objExt.Oid.FriendlyName == "Subject Key Identifier")
    {
        X509SubjectKeyIdentifierExtension ext = (X509SubjectKeyIdentifierExtension)objExt;
        objSB.AppendLine("    " + ext.SubjectKeyIdentifier);
    }

    if (objExt.Oid.FriendlyName == "Enhanced Key Usage") //2.5.29.37
    {
        X509EnhancedKeyUsageExtension ext = (X509EnhancedKeyUsageExtension)objExt;
        OidCollection objOids = ext.EnhancedKeyUsages;
        foreach (Oid oid in objOids)
            objSB.AppendLine("    " + oid.FriendlyName + " (" + oid.Value + ')');
    }
}
Debug.Print(objSB.ToString());

Validar certificados

Una de las tareas comunes que se realizan cuando estamos trabajando con certificados es la validación de los mismos. Esta tarea incluye verificar las fechas de validez, chequear que el certificado no haya sido revocado, etc. Esta validación debe hacerse en todos y cada uno de los certificados de la cadena hasta el certificado raíz.

Para validar la cadena de certificados se puede utilizar la clase X509Chain. Esta clase posee varias propiedades para especificar la forma en la que se quiere hacer la validación, por ejemplo, en la propiedad RevocationFlag se puede establecer si queremos validar sólo el certificado final (X509RevocationFlag.EndCertificateOnly), toda la cadena excepto el raíz (X509RevocationFlag.ExcludeRoot) o la cadena completa (X509RevocationFlag.EntireChain). También puede establecerse la forma en la que se quiere validar las revocaciones a través de la propiedad RevocationMode, pudiendo seleccionar en línea (X509RevocationMode.Online), fuera de línea (X509RevocationMode.Offline) o no chequear las listas de revocados (X509RevocationMode.NoCheck).

Para iniciar la validación, en la instancia de la clase X509Chain, se debe utilizar el método Build pasándole como parámetro el certificado. Luego de esto, en la propiedad ChainStatus, vamos a encontrar la lista de errores en las validaciones o, en caso de estar vacío este vector, significa que el certificado es válido.

Acá les dejo un código de ejemplo donde validamos un certificado y toda la cadena:

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
using System.Text;
...
X509Certificate2 objCert = ... //Acá tenemos que poner el certificado
X509Chain objChain = new X509Chain();

//Verifico toda la cadena de revocación
objChain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
objChain.ChainPolicy.RevocationMode = X509RevocationMode.Online;

//Timeout para las listas de revocación
objChain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 30);

//Verificar todo
objChain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

//Se puede cambiar la fecha de verificación
//objChain.ChainPolicy.VerificationTime = new DateTime(1999, 1, 1);

objChain.Build(objCert);

if (objChain.ChainStatus.Length != 0)
    foreach (X509ChainStatus objChainStatus in objChain.ChainStatus)
        Debug.Print(objChainStatus.Status.ToString() + " - " + objChainStatus.StatusInformation);
else
    Debug.Print("Ok");

Firma de datos

Una de las tareas más comunes para las cuales se utilizan los certificados es para firmar documentos. Para esto casi siempre se utiliza el estándar de sintaxis para mensajes criptográficos PKCS #7, el cual está definido en el RFC 2315.

En .NET, para crear firmas digitales utilizando PKCS #7, se pueden utilizar las clases que están en el namespace System.Security.Cryptography.Pkcs.
Pienso que lo mejor para explicar cómo hacerte esto es a través de un ejemplo, por lo tanto, a continuación muestro un ejemplo donde creo un documento con su firma digital a partir de un texto:

using System.Security.Cryptography.Pkcs;
using System.Diagnostics;
using System.Text;
...
X509Certificate2 objCert = ... //Acá tenemos que poner el certificado

//Creamos el ContentInfo
ContentInfo objContent = new ContentInfo(Encoding.ASCII.GetBytes("Scientia Soluciones Informáticas, la mejor consultora de desarrollo"));

//Creamos el objeto que representa los datos firmados
SignedCms objSignedData = new SignedCms(objContent);

//Creamos el "firmante"
CmsSigner objSigner = new CmsSigner(objCert);

//Firmamos los datos
objSignedData.ComputeSignature(objSigner);

//Obtenemos el resultado
byte[] bytSigned = objSignedData.Encode();

Debug.Print("Documento con firma: " + Convert.ToBase64String(bytSigned));

Otra opción, dependiendo de la forma en la que se quiere utilizar el resultado, es la de crear la firma solamente, sin el documento:

using System.Security.Cryptography.Pkcs;
using System.Diagnostics;
using System.Text;
...
X509Certificate2 objCert = ... //Acá tenemos que poner el certificado

//Creamos el ContentInfo
ContentInfo objContent = new ContentInfo(Encoding.ASCII.GetBytes("Scientia Soluciones Informáticas, la mejor consultora de desarrollo"));

//Creamos el objeto que representa los datos firmados
SignedCms objSignedData = new SignedCms(objContent, true);

//Creamos el "firmante"
CmsSigner objSigner = new CmsSigner(objCert);

//Firmamos los datos
objSignedData.ComputeSignature(objSigner);

//Obtenemos el resultado
byte[] bytSigned = objSignedData.Encode();

Debug.Print("Firma digital: " + Convert.ToBase64String(bytSigned));

Verificar firma

Obviamente si creamos un documento con una firma digital es porque, tarde o temprano, vamos a querer verificar esta firma. Para realizar esto utilizamos nuevamente la clase SignedCms, la cual posee el método CheckSignature, y en caso de ser un documento firmado (no la firma “suelta”), en la propiedad ContentInfo.Content va a estar el documento sin firma.

A continuación les dejo los dos ejemplos, la verificación de la firma digital:

using System.Security.Cryptography.Pkcs;
using System.Diagnostics;
using System.Text;
...
byte[] bytFirma = ... //Acá tenemos que poner la firma digital calculada en el ejemplo anterior
ContentInfo objContent = new ContentInfo(Encoding.ASCII.GetBytes("Scientia Soluciones Informáticas, la mejor consultora de desarrollo"));

SignedCms objDatos = new SignedCms(objContent, true);

//Deserealizamos la firma
objDatos.Decode(bytFirma);

try
{
//Verificamos si la firma concuerda con los datos
objDatos.CheckSignature(true);
Debug.Print("Ok - La firma concuerda con los datos");
}
catch
{
Debug.Print("Error - La firma no concuerda con los datos");
}

Y el ejemplo de la verificación de la firma y obtención del documento:

using System.Security.Cryptography.Pkcs;
using System.Diagnostics;
using System.Text;
...
byte[] bytDocFirmado = ... //Acá tenemos que poner el documento firmado obtenido en el ejemplo anterior
SignedCms objDatos = new SignedCms();

//Deserializo los bytes PKCS#7
objDatos.Decode(bytDocFirmado);

//Verifico la firma y obtengo el documento
try
{
    objDatos.CheckSignature(true);
    Debug.Print("Ok - La firma concuerda con los datos");
    Debug.Print(Encoding.ASCII.GetString(objDatos.ContentInfo.Content));
}
catch
{
    Debug.Print("Error - La firma no concuerda con los datos");
}

Encriptación y desencriptación utilizando un certificado

Por último voy a mostrar como encriptar y desencriptar documentos utilizando certificados digitales. Para esto, al igual con la firma de documentos, voy a mostrar un ejemplo, que creo es la mejor manera de entenderlo:

using System.Security.Cryptography.Pkcs;
using System.Diagnostics;
using System.Text;
...
X509Certificate2 objCert = ... //Acá tenemos que poner el certificado

//Creamos el ContentInfo
ContentInfo objContent = new ContentInfo(Encoding.ASCII.GetBytes("Scientia Soluciones Informáticas, la mejor consultora de desarrollo"));

//Creamos el objeto que representa los datos firmados
EnvelopedCms objEncryptedData = new EnvelopedCms(objContent);

//Creamos el destino
CmsRecipient objRecipient = new CmsRecipient(objCert);

//Firmamos los datos
objEncryptedData.Encrypt(objRecipient);

//Datos encriptados
byte[] bytResult = objEncryptedData.Encode();

Debug.Pring("Datos encriptados:  " + Convert.ToBase64String(bytResult));

Y ahora voy a mostrar como desencriptar los datos obtenidos en el paso anterior. Para esto previamente tenemos que tener instalado el certificado con el que se encriptaron estos datos, junto con su clave privada, en un repositorio sobre el cual el usuario tenga permisos:

using System.Security.Cryptography.Pkcs;
using System.Diagnostics;
using System.Text;
...
byte[] bytDatos = … //Datos encriptados

EnvelopedCms objEncryptedData = new EnvelopedCms();

//Leemos los datos encriptados
objEncryptedData.Decode(bytDatos);

//Desencriptamos los datos
objEncryptedData.Decrypt();

//Documento original
byte[] bytDoc = objEncryptedData.ContentInfo.Content;

//Mostramos el resultado
Debug.Print("Datos desencriptados: " + Encoding.ASCII.GetString(bytDoc));

Espero que este resumen pueda servirle a cualquier que necesite trabajar con certificados digitales desde .NET.

Artículos relacionados

VN:F [1.7.3_972]
Rating: 8.3/10 (3 votos cast)

Notificación de cambios en enlace a Data Objects con WPF

Martes, 18 ago, 2009 @ 18:07 | Por Dario Krapp | WPF

En un artículo previo llamado “Enlace a Data Objects en WPF” hemos comentado de que manera es posible enlazar un objeto de datos con uno o varios elementos WPF, hemos utilizado el markup Binding y modificado las propiedades Mode y UpdateSourceTrigger para controlar la transferencia de datos entre los objetos origen y destino.
Retomaremos desde el punto en el que habíamos quedado.
En nuestro articulo previo poseíamos la clase

public class Empl
{
   public int IDEmpleado { set; get; }
   public long? DNI { set; get; }
   public string Apellidos { set; get; }
   public string Nombres { set; get; }
   public DateTime FechaIngeso { set; get; }
}


La siguiente porción de XAML:

<StackPanel x:Name="stackPanelEmpl">
   <TextBox x:Name="txtIDEmpleado" Text="{Binding IDEmpleado}">   </TextBox>
    <TextBox x:Name="txtDNI" Text="{Binding DNI}"></TextBox>
    <TextBox x:Name="txtApellidos" Text="{Binding Apellidos}"> </TextBox>
    <TextBox x:Name="txtNombres" Text="{Binding Nombres}"></TextBox>
   <TextBox x:Name="txtFechaIngreso" Text="{Binding FechaIngeso}"></TextBox>
</StackPanel>


Y las siguientes líneas de código

 objE = new Empl()
   {
      Apellidos = "Perez",
      DNI = 29111222,
      FechaIngeso = new DateTime(2000, 11, 19),
      IDEmpleado = 123,
      Nombres = "Juan"
   };

    stackPanelEmpl.DataContext = objE;


El resultado de la ejecución de estas líneas era el enlace del objeto objE a los TextBoxes contenidos en el elemento stackPanelEmpl, pero este enlace tenía un problema potencial, si alguna propiedad del objeto objE era modificada externamente, el cambio no sería transferido a la interfaz gráfica. Un detalle que no habíamos comentado previamente es que la transferencia de datos desde el objeto origen hacia el objeto destino es siempre inmediato, la única excepción es que el Mode haya sido definido como OneTime, es importante recordar que la propiedad UpdateSourceTrigger (como su nombre da a entender) definirá como se actualizará la transferencia de datos en sentido inverso, o sea desde el objeto destino hacia el objeto origen, pero como ya mencionamos hace apenas dos líneas de texto la transferencia de datos desde el objeto origen hacia el objeto destino es siempre inmediata.

En este artículo nos centraremos en resolver el problema de avisar a la interfaz gráfica que una propiedad ha sido modificada y dejar que WPF haga el trabajo.

Quizás, aunque no lo parezca inicialmente, este sea un buen momento para mencionar que son las dependency properties. El uso de propiedades en los lenguajes de programación modernos no es para nada nuevo, se han venido utilizando en tecnologías previas desde hace varios años, pero WPF ha llegado con un nuevo tipo de propiedades denominadas dependecy properties, la diferencia fundamental es que en las dependency properties el valor de las mismas podría depender valores definidos en otros objetos, o sea provenir de diversas fuentes, por ejemplo de definiciones implícitas en el elemento, tanto como de la definición de las mismas en Templates, en Styles, en Resources, en Bindings, en herencia de sus elementos padre, etc. Al ser el valor de las propiedades de los elementos dependientes de tantos factores, no es una mala idea llevar a las propiedades a la mesa de dibujo e intentar redefinir una implementación que sea más eficiente en este contexto y agregarle de paso algunas características extra, como notificación de cambios, validación, etc.

Al utilizarse dependency properties se notará que se emplean como propiedades convencionales, esto no debe engañarnos, en WPF para cada dependency property existirá una propiedad convencional que funcionará como un wrapper y permitirá simplificar su utilización, pero no existe ninguna similitud. Por empezar las dependency properties serán manejadas y mantenidas por WPF, las mismas deberán declararse en un campo estático, público y de solo lectura. Además deberán registrarse, el siguiente ejemplo muestra la declaración de una dependency property en nuestra clase de ejemplo Empl destinada a almacenar los nombres del empleado:

public class Empl
   {
      public static readonly DependencyProperty NombresProperty = DependencyProperty.Register("Nombres", typeof(string), typeof(Empl));


La Dependency property ha sido llamada NombresProperty (el sufijo Property es una convención de WPF) y se ha registrado utilizando el método estático Register de la clase DependencyProperty, los parámetros pasados serán el nombre de la propiedad, el tipo de la misma y el tipo de la clase que registrará la propiedad. Como mencionamos previamente WPF se encargará de manejar y mantener el estado de las dependency properties, por ese motivo las mismas deberán registrarse (en el sistema de propiedades de WPF) y ser accesibles a nivel de clase (readonly asegurará que la dependency property no sea reasignada).

Por el momento solo hemos definido la dependency property, debemos ahora dar el proximo paso que consiste en brindar la posibilidad de establecer y leer su valor, en este punto toma importancia una clase llamada DependencyObject que representará a un objeto que formará parte del sistema de propiedades de WPF y nos brindará métodos para manejar (establecer o leer valores) la dependency property que ya hemos creado. Nuestra clase tomará la siguiente forma:

public class Empl: DependencyObject
   {
      public static readonly DependencyProperty NombresProperty = DependencyProperty.Register("Nombres", typeof(string), typeof(Empl));
      public string Nombres
      {
         set
            {
                SetValue(NombresProperty, value);
            }
            get
            {
                return GetValue(NombresProperty) as string;
            }
        }

	..

	....


Hemos heredado de la clase DependencyObject y hemos utilizado los métodos SetValue y GetValue que la misma nos ha proporcionado para manejar los valores de la dependency property, tambien hemos creado una propiedad wrapper denominada Nombres para manejar los valores de nuestra dependency property NombresProperty en forma más amigable.

La pregunta después de tanto código podría ser por que estuvimos hablando de dependency properties e hicimos todo esto. Pero en este caso (no como siempre sucede) hay un buen motivo, seguramente a estas alturas será de suponerse que utilizar
dependency properties nos permitirá resolver el problema que habíamos dejado pendiente, y efectivamente sucede de esa forma.
Con estas modificaciones la clase Empl podrá informar a elementos de la interfaz gráfica que su propiedad Nombres ha sido modificada, si en este momento la propiedad es modificada externamente, la interfaz gráfica notará el cambio inmediatamente. Ahora solo se deberá aplicar esta solución al resto de las propiedades.

Quienes hayan leído el artículo previo quizás recordarán que al mencionar las dependency properties comentamos que durante su definición era posible establecer los valores por defecto para las propiedades Mode y UpdateSourceTrigger utilizadas en el markup Binding.
Para poder definir estos valores, el método Register que ya hemos utilizado previamente cuenta con una sobrecarga que tomará un parámetro del tipo PropertyMetadata dónde podremos definir (junto con una infinidad de opciones), estas propiedades (en realidad utilizaremos un objeto del tipo FrameworkPropertyMetadata que heredará de PropertyMetadata), el código a continuación muestra una posibilidad para establecer estos valores.

public class Empl : DependencyObject
   {
        public static readonly DependencyProperty NombresProperty;

        static Empl()
        {
            FrameworkPropertyMetadata meta = new FrameworkPropertyMetadata()
            {
                BindsTwoWayByDefault = true,
                DefaultUpdateSourceTrigger = UpdateSourceTrigger.LostFocus
            };
            NombresProperty = DependencyProperty.Register("Nombres", typeof(string), typeof(Empl), meta);
        }

	..

	....


Parecería que todo ha quedado resuelto, pero no estará de más preguntarse que pasaria si no nos fuera posible hacer que nuestra clase Empl heredará de DependencyObject (lo cual no es una suposición muy inesperada). En este caso contaremos con otra posibilidad que nos permitirá obtener el mismo resultado, pero esta vez utilizando una interfaz.

La interfaz llamada INotifyPropertyChanged nos brindará un evento denominado PropertyChanged que deberemos invocar al momento de informar que propiedad ha cambiado, en este caso no utilizaremos dependency properties, solamente deberemos invocar al evento pasándole por parámetros el nombre de la propiedad que desearemos informar que ha sido modificada y una referencia al objeto que informará la modificación.
El código para nuestro caso será el siguiente:

public class Empl : INotifyPropertyChanged
    {
        string strNombre;
        public event PropertyChangedEventHandler PropertyChanged;

        public string Nombres
        {
            set
            {
                if (value != strNombre)
                {
                    strNombre = value;
                    if (PropertyChanged != null)
                        PropertyChanged(this, new PropertyChangedEventArgs("Nombres"));
                }
            }
            get
            {
                return strNombre;
            }
        }


Nuevamente será necesario extender la funcionalidad a cada propiedad que deseemos informar que ha sido modificada.

Finalmente cabe mencionar que existe una tercera posibilidad, la cual no requiere herencia ni interfaces. En este caso se deberá crear un evento a partir del delegado EventHandler y dispararlo cuando la propiedad haya sido modificada, en nuestro caso deberíamos utilizar las siguientes líneas de código:

    public class Empl
    {
        string strNombre;
        public event EventHandler NombresChanged = delegate { };

        public string Nombres
        {
            set
            {
                if (value != strNombre)
                {
                    strNombre = value;
                    NombresChanged(this, new EventArgs());
                }
            }
            get
            {
                return strNombre;
            }
        }


Un detalle fundamental es que para que el cambio sea informado el nombre del evento no podremos definirlo a nuestro gusto, el mismo deberá llamarse: nombre de propiedad + “Changed”, de aquí que en nuestro caso nos vimos obligados a definirlo como NombresChanged, que a decir verdad, no suena de lo mejor.

Como es de costumbre, espero que este artículo haya sido de utilidad y complemente los puntos pendiente del artículo anterior.

VN:F [1.7.3_972]
Rating: 9.0/10 (3 votos cast)

Como calcular el Hash de un vector de bytes o un string

Martes, 11 ago, 2009 @ 18:55 | Por Gustavo Cantero (The Wolf) | .NET Framework

Muchas veces necesitamos comparar un array de bytes, verificar que una contraseña es correcta sin almacenar la original o verificar la firma digital de un documento. Para realizar esto se puede crear el Hash del set de datos original y compararlo con el del nuevo. En el caso de la contraseña, se puede almacenar el Hash de la clave original y luego verificar que este dato sea igual al de la clave a comparar, logrando de esta manera que se pueda garantizar que aunque alguien pueda ingresar en la base de datos (incluso el mismo personal de la empresa) no podrán obtener la clave ingresada del usuario.
Para calcular el Hash primero hay que crear una instancia del algoritmo a utilizar, los cuales se encuentran en el namespace System.Security.Cryptography y heredan de la clase HashAlgorithm. Ejemplos de estas clases son RIPEMD160, MD5 y SHA512.

Luego de esto simplemente tenemos que invocar el método ComputeHash de la instancia pasándole el vector de bytes del cual se desea calcular el Hash. En caso de querer calcular el de un texto primero se deberá obtener los bytes del texto, por ejemplo, utilizando el método GetBytes de algún Enconding.

El Hash es otro vector de bytes por lo cual, si queremos mostrarlo en pantalla, podríamos convertirlo a base 64.

A continuación les dejo un ejemplo de cómo calcular el Hash de un string con el algoritmo SHA512 y guardarlo en otro string:

using System.Security.Cryptography;
using System.Text;
using System;
…
string strOriginal = &quot;Cadena de la cual calcular el hash&quot;;
byte[] bytOriginal = Encoding.ASCII.GetBytes(strOriginal);
SHA512 objAlgoritmo = SHA512.Create();
byte[] bytHash = objAlgoritmo.ComputeHash(bytOriginal);
string strHash = Convert.ToBase64String(bytHash);

Por último les dejo un pequeño proyecto hecho con WPF donde se calculo el hash de un texto ingresado utilizando distintos algoritmos.

Artículos relacionados

VN:F [1.7.3_972]
Rating: 7.0/10 (1 voto cast)