How does Visual Studio encrypt passwords in a .pubxml.user file?

Viewed 681

When you tell Visual Studio to save your password for a publish profile, it creates a .pubxml.user file next to your publish file looking something like the following:

<?xml version="1.0" encoding="utf-8"?>
<!--
This file is used by the publish/package process of your Web project. You can customize the behavior of this process
by editing this MSBuild file. In order to learn more about this please visit https://go.microsoft.com/fwlink/?LinkID=208121. 
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <TimeStampOfAssociatedLegacyPublishXmlFile />
    <EncryptedPassword>AQAAANC[...]</EncryptedPassword>
  </PropertyGroup>
</Project>

How does Visual Studio actually encrypt the password in the EncryptedPassword element? I'd like to decrypt it because I've forgotten my password... now it's just stored encrypted in this file!

1 Answers

The data are DPAPI encrypted. DPAPI encrypted data starts hexadecimal with the byte sequence 0x01000000D08C9DDF0115D1118C7A00C04FC297EB or Base64 encoded with AQAAANCMnd8BFdERjHoAwE/Cl+, here.

For decryption with C# the class ProtectedData or more precisely the static method ProtectedData.Unprotect can be used. If no value is known for the entropy s_aditionalEntropy, null should be tried. More information about this parameter can be found here.

If the encrypted data are Base64 encoded, they must be Base64 decoded before decryption:

using System.Security.Cryptography;

...
String encryptedDataB64 = "AQAAANCMnd8BFdERjHoAwE/Cl+...";
byte[] encryptedData = Convert.FromBase64String(encryptedDataB64); 

byte[] s_aditionalEntropy = null;
byte[] data = ProtectedData.Unprotect(encryptedData, s_aditionalEntropy, DataProtectionScope.CurrentUser); 

A more detailed example can be found in the linked documentation. The decryption is not limited to .NET, but is also possible with other languages, provided that a corresponding DPAPI-wrapper exists, e.g. in Python with win32crypt.CryptUnprotectData or in Java with Java DPAPI.

Here's a console program that gets the Unicode string representation of the decoded data:

using System;
using System.Security.Cryptography;

namespace ConsolePassDecrypter {
    class Program {
        static void Main(string[] args) {
            string encryptedPass = "AQAAANC[...]";
            var decryptedPassBytes = ProtectedData.Unprotect(Convert.FromBase64String(encryptedPass), null, DataProtectionScope.LocalMachine);
            Console.WriteLine("Decrypted pass: " + System.Text.Encoding.Unicode.GetString(decryptedPassBytes));
        }
    }
}
Related