[email protected]

Asunción, PARAGUAY

Ingeniería y desarrollo de software, emprendimiento, cursos

1 de abril de 2014

Silverlight: Cifrar y descifrar Strings (cadena de caracteres)

Silverlight

Introducción

En determinadas circunstancias resulta muy útil cifrar y descifrar las cadenas de caracteres en nuestras aplicaciones, especialmente cuando transmitimos datos sensibles a través de la red o entre aplicaciones dentro de nuestras propias máquinas.

En aplicaciones Silverlight podemos cifrar y descifrar las cadenas de caracteres fácilmente siguiendo algunos pasos y escribiendo unas cuantas líneas de código en una extensión de clase.

Contexto

Este artículo se ocupa de dos temas muy importantes:
  1. Cifrar y descifrar cadenas de caracteres dentro de una aplicación Silverlight (out-of-the-browser / fuera-del-navegador).
  2. Cifrar y descifrar cadenas de caracteres dentro de una aplicación de negocios Silverlight (donde existe comunicación entre Servicio y Aplicación Silverlight)
La idea principal aquí es demostrar cómo cifrar y descifrar el mismo valor en el servidor y en la aplicación cliente, debido a que la comunicación entre ellos se encuentran en texto sin formato.

Utilizando el código

Cifrar y descifrar cadena de caracteres dentro de una aplicación Silverlight

Muy bien, aquí debemos crear una sencilla Aplicación de negocios Silverlight en Visual Studio. En mi caso llamé a mi proyecto Encrypt_Decrypt_SBA.

Ahora crearemos un método de extensión para todas las cadenas de caracteres en nuestro proyecto Silverlight, la clase será estática y expondrá dos métodos principales: Encrypt()Decrypt(), tal como lo podemos ver a continuación:
namespace Encrypt_Decrypt_SBA.Helpers
{
    /// 
    /// Una simple clase disponible sólo en este Ensamblado
    /// 
    internal static class Cryptography
    {
        internal static string Encrypt(this string dataToEncrypt)
        {
            // Inicializamos
            AesManaged encryptor = new AesManaged();
            
            // Obtenemos el salto de cadena, en este caso lo hacemos estáticamente. Luego creamos el objeto byte[]
            string salt = "EDSBA_EXAMPLE";
            byte[] saltBytes = new UTF8Encoding().GetBytes(salt);
            Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(salt, saltBytes);

            encryptor.Key = rfc.GetBytes(16);
            encryptor.IV = rfc.GetBytes(16);
            encryptor.BlockSize = 128;

            // Creamos el objeto Stream en memoria
            using (MemoryStream encryptionStream = new MemoryStream())
            {
                // Creamos el Stream de criptografía
                using (CryptoStream encrypt = new CryptoStream(encryptionStream, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    // Ciframos
                    byte[] utfD1 = UTF8Encoding.UTF8.GetBytes(dataToEncrypt);
                    encrypt.Write(utfD1, 0, utfD1.Length);
                    encrypt.FlushFinalBlock();
                    encrypt.Close();

                    // Retornamos el dato cifrado
                    return Convert.ToBase64String(encryptionStream.ToArray());
                }
            }
        }

        internal static string Decrypt(this string encryptedString)
        {
            // Inicializamos variables
            AesManaged decryptor = new AesManaged();
            byte[] encryptedData = Convert.FromBase64String(encryptedString);

            // Obtenemos el salto de la cadena, en este caso lo pasamos estáticamente. Luego, creamos el objeto byte[]
            string salt = "EDSBA_EXAMPLE";
            byte[] saltBytes = new UTF8Encoding().GetBytes(salt);
            Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(salt, saltBytes);

            decryptor.Key = rfc.GetBytes(16);
            decryptor.IV = rfc.GetBytes(16);
            decryptor.BlockSize = 128;

            // Creamos un Stream en memoria
            using (MemoryStream decryptionStream = new MemoryStream())
            {
                // Creamos un Stream de criptografía
                using (CryptoStream decrypt = new CryptoStream(decryptionStream, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    try
                    {
                        // Desciframos
                        decrypt.Write(encryptedData, 0, encryptedData.Length);
                        decrypt.Flush();
                        decrypt.Close();
                    }
                    catch { }

                    // Retornamos el dato descifrado
                    byte[] decryptedData = decryptionStream.ToArray();
                    return UTF8Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
                }
            }
        }
    }
}
En el código anterior, hemos creado dos métodos extensibles para todas las cadenas de caracteres dentro del proyecto Silverlight, de esta manera que podemos implementar fácilmente el cifrado de cualquier cadena de caracteres dentro del proyecto.

¡Ejecutamos el proyecto (F5) y lo probamos!

Cifrar y descifrar cadenas de caracteres en una Aplicación de Negocios Silverlight

En este caso, tenemos que crear una clase para implementar el mismo algoritmo que utilizamos en nuestra aplicación Silverlight.

Entonces podemos crear la misma clase y exponer el mismo conjunto de métodos dentro de ella, así que el código será:
namespace Encrypt_Decrypt_SBA.Web
{
    /// 
    /// Una simple clase disponible sólo en este ensamblado
    /// 
    internal static class Cryptography
    {
        internal static string Encrypt(this string dataToEncrypt)
        {
            // Inicializamos
            AesManaged encryptor = new AesManaged();

            // Obtenemos el salto de cadena, en este caso lo pasamos estáticamente. Luego, creamos el objeto byte[]
            string salt = "EDSBA_EXAMPLE";
            byte[] saltBytes = new UTF8Encoding().GetBytes(salt);
            Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(salt, saltBytes);

            encryptor.Key = rfc.GetBytes(16);
            encryptor.IV = rfc.GetBytes(16);
            encryptor.BlockSize = 128;

            // Creamos un Stream en memoria
            using (MemoryStream encryptionStream = new MemoryStream())
            {
                // Creamos el stream de criptografía
                using (CryptoStream encrypt = new CryptoStream(encryptionStream, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    // Cifrar
                    byte[] utfD1 = UTF8Encoding.UTF8.GetBytes(dataToEncrypt);
                    encrypt.Write(utfD1, 0, utfD1.Length);
                    encrypt.FlushFinalBlock();
                    encrypt.Close();

                    // Retornar el dato cifrado
                    return Convert.ToBase64String(encryptionStream.ToArray());
                }
            }
        }

        internal static string Decrypt(this string encryptedString)
        {
            // Inicializamos
            AesManaged decryptor = new AesManaged();
            byte[] encryptedData = Convert.FromBase64String(encryptedString);

            // Obtenemos el salto de cadena, en este caso lo pasamos estáticamente. Luego, creamos el objeto byte[]
            string salt = "EDSBA_EXAMPLE";
            byte[] saltBytes = new UTF8Encoding().GetBytes(salt);
            Rfc2898DeriveBytes rfc = new Rfc2898DeriveBytes(salt, saltBytes);

            decryptor.Key = rfc.GetBytes(16);
            decryptor.IV = rfc.GetBytes(16);
            decryptor.BlockSize = 128;

            // Creamos el Stream en memoria
            using (MemoryStream decryptionStream = new MemoryStream())
            {
                // Creamos el Stream de criptografía
                using (CryptoStream decrypt = new CryptoStream(decryptionStream, decryptor.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    try
                    {
                        // Desciframos
                        decrypt.Write(encryptedData, 0, encryptedData.Length);
                        decrypt.Flush();
                        decrypt.Close();
                    }
                    catch { }

                    // Retornar el dato descifrado
                    byte[] decryptedData = decryptionStream.ToArray();
                    return UTF8Encoding.UTF8.GetString(decryptedData, 0, decryptedData.Length);
                }
            }
        }
    }
}
Ahora vamos a crear un Servicio WCF para Silverlight, dentro de la carpeta de servicios. La llamaremos ServiceTest.svc y crearemos los dos métodos siguientes:
namespace Encrypt_Decrypt_SBA.Web.Services
{
    [ServiceContract(Namespace = "")]
    [SilverlightFaultBehavior]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class ServiceTest
    {
        [OperationContract]
        public void DoWork()
        {
            return;
        }

        [OperationContract]
        public string EncryptString(string unencrypted)
        {
            return unencrypted.Encrypt();
        }

        [OperationContract]
        public string DecryptString(string encrypted)
        {
            return encrypted.Decrypt();
        }
    }
}
Compilamos el proyecto Web. Y agregamos la referencia de servicio en la Aplicación Silverlight

Ahora, sólo llamaremos a la cadena de caracteres cifrada en el servidor y comprobaremos con el Texto de la aplicación Silverlight, de esta manera:
private void btnEncryptService_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            //Instanciamos el proxy para el servicio ServiceTest
            ServiceTest.ServiceTestClient proxy = new ServiceTest.ServiceTestClient();
            //Llamamos al procedimiento desde el proxy
            proxy.EncryptStringCompleted += (s, args) =>
            {
                this.simpleTextService.Text = string.Empty;
                this.EncryptedTextService.Text = args.Result;
            };
            //Llamamos al método async y pasamos el parámetro
            proxy.EncryptStringAsync(this.simpleTextService.Text);
        }

        private void btnDencryptService_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            //Instanciamos el proxy para el servicio ServiceTest
            ServiceTest.ServiceTestClient proxy = new ServiceTest.ServiceTestClient();
            //Llamamos al procedimiento del proxy
            proxy.DecryptStringCompleted += (s, args) =>
            {
                MessageBox.Show("Vía servicio: "+args.Result);
                this.EncryptedTextService.Text = string.Empty;
            };
            //Llamar al método async y pasar el parámetro
            proxy.DecryptStringAsync(this.EncryptedTextService.Text);
        }

Copyright

El algoritmo de criptografía no es mío. He descargado de aquí hace unos años atrás. Así que, el algoritmo existe gracias a chrishayuk.

Puntos de interés

Este artículo expone cómo puede implementar cifrado y descifrado de cualquier cadena de caracteres en una aplicación Silverlight y también en el servidor. Es muy importante en algunos casos. Sé que puede crear tantas maneras de implementar este escenario. Esto es sólo una manera de hacerlo.

Hey, we've just launched a new custom color Blogger template. You'll like it - https://t.co/quGl87I2PZ
Suscribíte al boletín