Cómo desencriptar una password de RDP de Azure olvidada

password-decrypting-600x394¿Alguna vez te ha pasado que has olvidado la contraseña que pusiste al publicar tu servicio hospedado en Azure y ahora no te puedes conectar por RDP?

Actualmente, hay una solución muy sencilla –y recomendada-, que es volver a restablecer la contraseña a través del portal de Windows Azure, siguiendo los pasos siguientes:

  1. Acceder al portal de Windows Azure
  2. Ir al servicio hospedado e ir a la sección “Configurar”
  3. Hacer click en el botón “Remoto” de la barra de herramientas inferior
  4. Restablecer la contraseña introduciéndola en los campos solicitados, reconfigurando así las credenciales del usuario RDP.

ResetPassword

Esto cambiará el estado del role a “Actualizando” y al cabo de unos minutos ya podremos acceder con la nueva contraseña.

Si bien esta operación restablece correctamente los credenciales, a veces no nos conviene por un motivo u otro realizar este cambio. Así que aquí va el truco siguiente.

Desencriptar una contraseña RDP olvidada de Windows Azure

Para poder desencriptar la contraseña olvidada necesitamos:

  • Tener la cadena de texto de la contraseña encriptada
  • Tener instalado en el equipo local el certificado con la que fue encriptada

La contraseña encriptada se almacena en el archivo .cscfg con el que fue desplegado tu servicio, si bien éste puede ser distinto si alguien la ha modificado siguiendo el método anterior. Para asegurarnos de tener la última contraseña, puedes seguir los pasos siguientes:

  1. Acceder al portal anterior de Windows Azure a través de la URL https://windows.azure.com (te solicitará tus credenciales) y luego mostrará la versión anterior del portal en Silverlight
  2. Ir al servicio en cuestión y seleccionar el despliegue. En la parte derecha aparecerán las propiedades del mismo con los valores actuales
  3. Copiar al portapapeles el valor de la propiedad “Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountEncryptedPassword”

PasswordEncripted

Ahora que tienes la contraseña, puedes usar el certificado almacenado en tu almacén de certificados local para desencriptarla, del mismo modo que hace el agente de RDP de Windows Azure para crear las credenciales en el role startup.

El código para ello sería la función siguiente:

   1: private static string DecryptPassword(string encryptedPassword)

   2: {

   3:     if (string.IsNullOrEmpty(encryptedPassword))

   4:     {

   5:         throw new ArgumentNullException("encryptedPassword");

   6:     }

   7:     SecureString secPassword;

   8:     try

   9:     {

  10:         var encryptedBytes = Convert.FromBase64String(encryptedPassword);

  11:         var envelope = new EnvelopedCms();

  12:         envelope.Decode(encryptedBytes);

  13:         var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

  14:         store.Open(OpenFlags.ReadOnly);

  15:         envelope.Decrypt(store.Certificates);

  16:         char[] passwordChars = Encoding.UTF8.GetChars(envelope.ContentInfo.Content);

  17:         secPassword = new SecureString();

  18:         foreach (var character in passwordChars)

  19:         {

  20:             secPassword.AppendChar(character);

  21:         }

  22:         Array.Clear(envelope.ContentInfo.Content, 0, envelope.ContentInfo.Content.Length);

  23:         Array.Clear(passwordChars, 0, passwordChars.Length);

  24:         secPassword.MakeReadOnly();

  25:     }

  26:     catch (CryptographicException cex)

  27:     {

  28:         throw new SecurityException("Unable to decrypt password. Make sure that the cert used for encryption was uploaded to the Azure service", cex);

  29:     }

  30:     catch (FormatException fex)

  31:     {

  32:         throw new SecurityException("Encrypted password is not a valid base64 string", fex);

  33:     }

  34:  

  35:     return GetUnsecuredString(secPassword);

  36: }

  37:  

  38: private static string GetUnsecuredString(SecureString secureString)

  39: {

  40:     if (secureString == null)

  41:     {

  42:         throw new ArgumentNullException("secureString");

  43:     }

  44:  

  45:     IntPtr ptrUnsecureString = IntPtr.Zero;

  46:     try

  47:     {

  48:         ptrUnsecureString = Marshal.SecureStringToGlobalAllocUnicode(secureString);

  49:         return Marshal.PtrToStringUni(ptrUnsecureString);

  50:     }

  51:     finally

  52:     {

  53:         Marshal.ZeroFreeGlobalAllocUnicode(ptrUnsecureString);

  54:     }

  55: }

  56:  

Adjunto una solución con el código de ejemplo por si alguno le interesa.

Un saludo y happy coding!

Deja un comentario

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