Cifrando Strings con un password

Puede ser… que el cifrado del archivo de configuración de tu aplicación no se adecue a la solución que buscas… puede ser… que necesites cifrar cadenas concretas en un archivo… en una base de datos… mandar eMails cifrados a tu novia/mujer/amante…  lo que sea…

Estas dos funciones, basadas en el ejemplo de este artículo con algunas modificaciones, cifran y descifran un String con el algoritmo simétrico Rijndael y con una palabra clave que se pasa como SecureString (¿Por qué?). De esta forma, podemos cifrar/descifrar un texto/cadena mediante ese password.

Necesitamos estos namespaces adicionales:

using System.IO;
using System.Security;
using System.Security.Cryptography;
using System.Runtime.InteropServices;

La función de cifrado:

public static string EncryptString(String Text, SecureString Password)
{
  String encryptedString = null;
  RijndaelManaged cipher = new RijndaelManaged();
  IntPtr bstr = IntPtr.Zero;
  try
  {
    bstr = Marshal.SecureStringToBSTR(Password);
    Byte[] passBytes = System.Text.Encoding.Unicode.GetBytes(Text);
    Byte[] saltBytes = Encoding.ASCII.GetBytes(Password.Length.ToString());
    PasswordDeriveBytes secret = new PasswordDeriveBytes(Marshal.PtrToStringUni(bstr), saltBytes);
 
    using (ICryptoTransform encryptor = cipher.CreateEncryptor(secret.GetBytes(32), secret.GetBytes(16)))
    using (MemoryStream ms = new MemoryStream())
    using (CryptoStream cryptoStream = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
    {
      cryptoStream.Write(passBytes, 0, passBytes.Length);
      cryptoStream.FlushFinalBlock();
      encryptedString = Convert.ToBase64String(ms.ToArray());
    }
  }
  finally
  {
    if (IntPtr.Zero != bstr)
      Marshal.ZeroFreeBSTR(bstr);
  }
 
  return encryptedString;
}

La función de descifrado:

public static string DecryptString(String Text, SecureString Password)
{
  String decryptedString = null;
  RijndaelManaged cipher = new RijndaelManaged();
  IntPtr bstr = IntPtr.Zero;
  try
  {
    bstr = Marshal.SecureStringToBSTR(Password);
    Byte[] encryptedBytes = Convert.FromBase64String(Text);
    Byte[] saltBytes = Encoding.ASCII.GetBytes(Password.Length.ToString());
    PasswordDeriveBytes secret = new PasswordDeriveBytes(Marshal.PtrToStringUni(bstr), saltBytes);
 
    using (ICryptoTransform decryptor = cipher.CreateDecryptor(secret.GetBytes(32), secret.GetBytes(16)))
    using (MemoryStream memoryStream = new MemoryStream(encryptedBytes))
    using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
    {
      Byte[] PlainText = new Byte[encryptedBytes.Length];
      Int32 DecryptedCount = cryptoStream.Read(PlainText, 0, PlainText.Length);
      decryptedString = Encoding.Unicode.GetString(PlainText, 0, DecryptedCount);
    }
  }
  finally
  {
    if (IntPtr.Zero != bstr)
      Marshal.ZeroFreeBSTR(bstr);
  }
 
  return decryptedString;
}

Podemos probarlo en un pequeño programa:

static void Main(string[] args)
{
  String data = "## Prueba de cifrado ##";
  
  SecureString secureS = new SecureString();
  secureS.AppendChar('m');
  secureS.AppendChar('y');
  secureS.AppendChar('p');
  secureS.AppendChar('a');
  secureS.AppendChar('s');
  secureS.AppendChar('s');
 
  Console.WriteLine("     Plano: " + data); 
 
  String encryptedData = Cipher.EncryptString(data,secureS);
  
  Console.WriteLine("   Cifrado: " + encryptedData);
  
  Console.WriteLine("Descifrado: " + Cipher.DecryptString(encryptedData,secureS)); 
 
  Console.ReadKey(true);
  secureS.Dispose();
}

Resultado:

image

Cifrando Strings con un password | vtortola.NET

MSMQ: Mensajes atascados en las colas de Outgoing

Si con MSMQ 3.0 y Windows 2003 Server SP2 se te amontonan los mensajes en las colas de Outgoing (salida)… haciendo que tarden en entregarse ó incluso que lleguen a caducar allí… antes de liarse a patadas con nada… existen diversos motivos por los que puede suceder:

  • Los más básicos, problemas de conectividad, de resolución de nombres, de permisos, de acceso…. conviene repasar este FAQ.
  • Tienes activado el modo Hardened MSMQ.
  • Las colas tienen cuotas pequeñas y los journals están llenos.
  • La red tiene una conectividad cuestionable (alta latencia, bajo ancho de banda, packetloss, …etc…) y MSMQ falla a menudo en entregar los mensajes, lo cual hace que tenga que esperar 60 segundos para el reintento. Hasta el SP1 el tiempo de espera entre reintentos era de 5 segundos (algo razonable, pero 60?!… ), para cambiar este valor hay que añadir la clave WaitTime al registro de Windows en su sección para MSMQ.
  • Tienes una cantidad ingente de colas de salida y una conectividad cuestionable:
    • Si se usa una topología en estrella ó consideras más que suficiente el ancho de banda como para comunicarte con el resto de máquinas puedes aumentar la cantidad de hilos disponibles en el thread pool de MSMQ para agilizar el envio añadiendo la clave QMThreadNo al registro de Windows en su sección para MSMQ. De esta forma, aunque las transferencias sean lentas… se podrán paralelizar más de ellas.
    • Si no, puedes recurrir a comprimir el contenido de los mensajes (no incluido en MSMQ 3.0) mediante por ejemplo los algoritmos de compresión GZip ó Deflate.
MSMQ: Mensajes atascados en las colas de Outgoing | vtortola.NET

Servicios Windows instalables

gear Aquí va un pequeño How-to rápido de como se crea e instala un servicio Windows con .NET y Visual Studio 2005 dedicado a mi compañero Juanma Otero que a cambio me explicará como funcionan los EndPoints de SQL Server 😀

Cada vez que vayamos a crear un servicio Windows, podemos seguir estos pasos para crear lo que sería el contenedor y su capacidad de instalación, para luego más tranquilamente empezar a introducir la lógica y funcionalidad del negocio que le queramos dar.

 

1. Creando.

empezando Se utiliza un proyecto Windows Service, que digamos es un contenedor en el que tenemos que implementar las acciones básicas de un servicio como son Start, Stop, Pause, Restar… etc.. En un próximo artículo me meteré un poco más a fondo en el tema de la implementación , como usar el EventLog… etc.. etc..

 

 

 

2. Haciéndolo instalable.

InstallerClass Añadimos al proyecto una Installer Class desde el menu «Add New Item», que nos provee la funcionalidad de instalación. Hay dos componentes que no están en la paleta que nos hacen falta, aunque se puede hacer «a pelo» … siempre los añado…

 

 

 

 

 

componentes Añadimos a la paleta de componentes las clases ServiceInstaller y ServiceProcessInstaller . Añadimos estos componentes al diseñador de la clase instaladora y los configuramos. No hay mucho que configurar 😛

 

 

 

ServiceInstaller En el ServiceInstaller, configuramos el nombre que mostrará, la descripción, el nombre por el que invocaremos al servicio y el tipo incio. Ponemos que el «Parent» es la clase InstallerClass.

 

 

 

 

 

ServiceProcessInstaller En el ServiceProcessInstaller configuramos la cuenta de usuario con la que se ejecutará el servicio, por lo general LocalService que es una cuenta con pocos privilegios. Ponemos que el «Parent» es la clase instaladora.

 

 

 

 

3. El instalador.

Instalador Añadimos al a solución un proyecto «Setup Project» que nos provee de la funcionalidad de un asistente instalador.

 

 

 

 

 

addprojectoutput Dentro de este proyecto, vamos al «File System Editor» y en «Application Folder» le decimos «Add Project Output», seleccionamos «Primary Output», nuestro proyecto en el combo y configuracion (Active) (para que use la que nosotros usemos … Debug ó Release).

 

 

 

 

 

actionsoutput Ahora vamos al «Custom Actions Editor» y directamente sobre el elemento «Custom Actions» añadimos la salida del proyecto que hemos puesto en «Application Folder».

 

 

 

 

4. Instalando.

Install Construimos la solución y el proyecto de instalación, este último genera un paquete .msi y un .exe asociado, con eso ya se puede instalar por ahí 😀 pero para trabajar en desarrollo nada más comodo que botón derecho e Install 😉

 

 

 

Lo instalamos y vemos que ya aparece en nuestra consola de administración de servicios. Podemos iniciarlo, pararlo, reiniciarlo… etc…

mmc

5. Haciendo que se inicie automáticamente al instalarlo.

Si, aunque se configure que debe iniciarse automáticamente… eso será en el próximo reinicio de la máquina. Para que se inicie automáticamente la primera vez … nos suscribimos al evento AfterInstall del componente ServiceInstaller que añadimos a la clase instaladora y hacemos que el servicio arranque con ServiceController:

private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
  using (ServiceController svc = new ServiceController("MiServicio"))
    svc.Start();
}

Con esto una vez el servicio este instalado automáticamente se iniciará.

Ahora podemos ponernos manos a la obra en integrar nuestra lógica dentro del servicio. Yo por comodidad… creo un proyecto «Console Application» normal para desarrollo y primeras pruebas, cuando ya esta todo listo… integro los ensamblados en el servicio, pero bueno… «cada maestrillo tiene su librillo…» 🙂

vtortola.Net | Servicios Windows Instalables