Encrypting Passwords in a .NET app.config File - Jon Galloway

Encrypting Passwords in a .NET app.config File

I've been contributing to the Witty project lately. I'm a fan of Twitter, and it's nice to work on a popular WPF application with some hotshot coders including a WPF pro like Alan Le. Lately, I noticed that we were storing the user's password in plaintext application config file:

<setting name="Password" serializeAs="String"> 
    <value>OOPS-WE-STORED-THE-PASSWORD-IN-PLAINTEXT</value> 
</setting>

So, yeah, that's less than ideal. Foolishly, I volunteered to fix it. There's plenty of information on encrypting ASP.NET configuration settings in web.config files, but encrypting settings in a desktop application isn't as well documented. Here's what I came up with.

DPAPI, Papi!

The best way to encrypt configuration settings is with DPAPI, the Data Protection Application Programmer's Interface:

This Data Protection API (DPAPI) is a pair of function calls that provide OS-level data protection services to user and system processes. By OS-level, we mean a service that is provided by the operating system itself and does not require any additional libraries. By data protection, we mean a service that provides confidentiality of data through encryption. Since the data protection is part of the OS, every application can now secure data without needing any specific cryptographic code other than the necessary function calls to DPAPI.

That sounds pretty good. But is it secure? Let's ask old man Wikipedia:

The keys used for encrypting the user's keys are stored under "%USERPROFILE%\Application Data\Microsoft\Protect\{SID}", where {SID} is the security identifier of that user. The DPAPI key is stored in the same file as the master key that protects the users private keys. It usually is 40 bytes of random data. DPAPI doesn't store any persistent data for itself; instead, it simply receives plaintext and returns cryptext (or vice-versa).

DPAPI security relies upon the system's ability to protect the Master Key and RSA private keys from compromise, which in most attack scenarios is most highly reliant on the security of the end user's credentials. Particular data binary large objects can be encrypted in a way that salt is added and/or an external user-provided password (aka "Strong Key Protection") is required. The use of a salt is a per-implementation option - i.e. under the control of the application developer - not controllable by the end user or IT professional.

Yeah, I didn't read it either. I did check the footnotes and saw that nobody's bragging about yoinking data out of it, though. And it has to  be better than storing passwords in plaintext. So, awesome, let's go for it!

The Nuclear Option: Encrypt The Whole Thing

The easiest way to deal with the problem is to just encrypt the entire section. That's because the ConfigurationSection knows how to protect itself, like so:

protected override void OnStartup(StartupEventArgs e) 
{ 
    // Lots of other important stuff here... 
    EncryptConfigSection("userSettings/Witty.Properties.Settings"); 
    base.OnStartup(e); 
}

private void EncryptConfigSection(string sectionKey)
{
    Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
    ConfigurationSection section = config.GetSection(sectionKey);
    if (section != null)
    {
        if (!section.SectionInformation.IsProtected)
        {
            if (!section.ElementInformation.IsLocked)
            {
                section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");
                section.SectionInformation.ForceSave = true;
                config.Save(ConfigurationSaveMode.Full);
            }
        }
    }
}

 

Once we've done that, the entire settings section is encrypted and placed in a <CipherValue> block:

<userSettings>
 <Witty.Properties.Settings configProtectionProvider="DataProtectionConfigurationProvider">
  <EncryptedData>
    <CipherData>
      <CipherValue>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAABbLHX[...]</CipherValue>
    </CipherData>
  </EncryptedData>
 </Witty.Properties.Settings>
</userSettings>

That's great from a security standpoint, but by encrypting everything, we've unnecessarily restricted access to all the information in the configuration file.

<userSettings> 
<Witty.Properties.Settings> 
  <setting name="Username" serializeAs="String"> 
    <value>UserNameGoesHere</value> 
  </setting> 
  <setting name="Password" serializeAs="String"> 
    <value>OOPS-WE-STORED-THE-PASSWORD-IN-PLAINTEXT</value> 
  </setting> 
  <setting name="RefreshInterval" serializeAs="String"> 
    <value>5</value> 
  </setting> 
  <setting name="LastUpdated" serializeAs="String"> 
    <value /> 
  </setting> 
  <setting name="PlaySounds" serializeAs="String"> 
    <value>True</value> 
  </setting> 
  ... 
</Witty.Properties.Settings> 
</userSettings>

So, what would be better is to encrypt just the password. To do that, we'll need to look into SecureString and System.Security.Cryptography.ProtectedData.

What's With The SecureString?

Like just about everything to do with ASP.NET development, David Hayden told us everything we need to know about SecureString years ago. The short story is that a System.String hangs around in memory until the garbage collector picks it up, so even if we're encrypting passwords or other sensitive data in our configuration file, it's possible to snag them from memory if we're using a standard System.String. SecureString uses our old friend DPAPI to encrypt values, so they're safe from memory snooping.

It's not as great as it sounds, though, because few API's accept or return SecureStrings. While it's a good practice to use SecureStrings when we can, we'll have to convert to and from standard System.String values at some point. While we're looking at security, we might as well use SecureStrings when possible, but we should keep in mind the fact that it's totally futile. Well, not that bad, but there are times where the sensitive information is still stored as insecure strings in memory.

Encrypting Strings with ProtectedData

So here's the actual meat of this post - the code I used to encrypt passwords in Witty's configuration. We've got two main methods, EncryptString and DecryptString. They both call in to ToSecureString and ToUnsecureString (great name, huh?) whose purpose should be pretty self-explanatory.

static byte[] entropy = System.Text.Encoding.Unicode.GetBytes("Salt Is Not A Password");

public static string EncryptString(System.Security.SecureString input)
{
    byte[] encryptedData = System.Security.Cryptography.ProtectedData.Protect(
        System.Text.Encoding.Unicode.GetBytes(ToInsecureString(input)),
        entropy,
        System.Security.Cryptography.DataProtectionScope.CurrentUser);
    return Convert.ToBase64String(encryptedData);
}

public static SecureString DecryptString(string encryptedData)
{
    try
    {
        byte[] decryptedData = System.Security.Cryptography.ProtectedData.Unprotect(
            Convert.FromBase64String(encryptedData),
            entropy,
            System.Security.Cryptography.DataProtectionScope.CurrentUser);
        return ToSecureString(System.Text.Encoding.Unicode.GetString(decryptedData));
    }
    catch
    {
        return new SecureString();
    }
}

public static SecureString ToSecureString(string input)
{
    SecureString secure = new SecureString();
    foreach (char c in input)
    {
        secure.AppendChar(c);
    }
    secure.MakeReadOnly();
    return secure;
}

public static string ToInsecureString(SecureString input)
{
    string returnValue = string.Empty;
    IntPtr ptr = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
    try
    {
        returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(ptr);
    }
    finally
    {
        System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(ptr);
    }
    return returnValue;
}

Then we're pretty much set. When we want to encrypt passwords for storage, we'll make a call like this:

AppSettings.Password = EncryptString(ToSecureString(PasswordTextBox.Password));

And we can get the password back out with this kind of thing:

SecureString password = DecryptString(AppSettings.Password)

The payoff is that our configuration looks like this:

<Witty.Properties.Settings>
    <setting name="Username" serializeAs="String">
        <value>jongalloway</value>
    </setting>
    <setting name="Password" serializeAs="String">
        <value>AQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAV[lots more stuff that's not my password]</value>
    </setting>
    <setting name="RefreshInterval" serializeAs="String">
        <value>5</value>
    </setting>
    <setting name="LastUpdated" serializeAs="String">
        <value>4/11/2008 12:10:33 AM</value>
    </setting>
</Witty.Properties.Settings>
For further study:
http://msdn2.microsoft.com/en-us/library/system.configuration.dpapiprotectedconfigurationprovider.aspx
http://www.codeproject.com/KB/security/ProtectedConfigWinApps.aspx
http://www.builderau.com.au/program/dotnet/soa/Encrypting-NET-configuration-files-through-code/0,339028399,339281837,00.htm
Published Sunday, April 13, 2008 2:20 AM by Jon Galloway

Comments

# Dew Drop - April 13, 2008 | Alvin Ashcraft's Morning Dew

Pingback from  Dew Drop - April 13, 2008 | Alvin Ashcraft's Morning Dew

# Encrypting Passwords in a .NET app.config File

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Sunday, April 13, 2008 11:06 AM by DotNetKicks.com

# re: Encrypting Passwords in a .NET app.config File

You should clear out the encryptedData and decryptedData byte arrays once you are done with them using Array.Clear(..).

Raj

Sunday, April 13, 2008 1:33 PM by rajbk

# Encrypting configuration information in .NET (web/windows)

Encrypting configuration information in .NET (web/windows)

Sunday, April 13, 2008 8:49 PM by .NET Developer Notes

# asp net programmer

Pingback from  asp net programmer

Monday, April 14, 2008 2:49 AM by asp net programmer

# Mind Gravy &raquo; Blog Archive &raquo; links for 2008-04-14

Pingback from  Mind Gravy  &raquo; Blog Archive   &raquo; links for 2008-04-14

Monday, April 14, 2008 8:41 AM by Mind Gravy » Blog Archive » links for 2008-04-14

# re: Encrypting Passwords in a .NET app.config File

The salt is presumably worthless, given the existence of Reflector. I suppose is has some worth, in that it adds a small layer of extra obfuscation.

And if a bad guy can get at the config file to read it, I wonder how hard it would be to run the DPAPI to decrypt it...

Is this more than security through obscurity? Genuine question to any security experts out there.

Monday, April 14, 2008 5:10 PM by commenter

# re: Encrypting Passwords in a .NET app.config File

<i>Is this more than security through obscurity? Genuine question to any security experts out there.</i>

Good question

Tuesday, April 15, 2008 2:38 AM by junko

# re: Encrypting Passwords in a .NET app.config File

IMO, this *is* security through obscurity. In addition one would use a key generation logic for the entropy (instead of a string) and use a code obfuscator to add an additional layer of obscurity.

Raj

Tuesday, April 15, 2008 10:02 AM by rajbk

# re: Encrypting Passwords in a .NET app.config File

If the badguy has access to your Windows account then this kind of protection is useless.

This is more of a protection against someone reading your config from another Windows account.  (as far as i can tell)

Also, the additional entropy feels more like an IV then a salt?

Tuesday, April 15, 2008 11:49 AM by JJ

# re: Encrypting Passwords in a .NET app.config File

@commenter I agree that the salt adds little to the security of the system, since it's required to the same on encryption and decryption. I'd still use it, since it would provide another level of protection over automated attacks.

Wednesday, April 16, 2008 12:20 PM by Jon Galloway

# re: Encrypting Passwords in a .NET app.config File

@junko, @rajbk, @JJ

If you're interested in the security of the system, please read the link I included.

msdn2.microsoft.com/.../ms995355.aspx

I joked about it because I didn't want to get into it in detail, but it is much more than security by obscurity, and it's not useless if an attacker has access to your Windows account.

For instance, encryption uses published standard encryption algorithms like Triple-DES that provide a level of security which is more than sufficient for most applications. Also, DPAPI uses the user's password, so an attacker would need both authenticated access to my filesystem and my system password to access my data. It's hard to expect that the system should prevent access to an attacker with both filesystem access and my account password, right?

Wednesday, April 16, 2008 12:40 PM by Jon Galloway

# storing data

Pingback from  storing data

Thursday, April 17, 2008 9:03 PM by storing data

# re: Encrypting Passwords in a .NET app.config File

Is someone had your system password, I think it wouldn't be to hard for him to get authenticated access to your filesystem :)

Friday, May 02, 2008 3:18 PM by Tibon

# asp net programmer

Pingback from  asp net programmer

Friday, May 09, 2008 2:24 AM by asp net programmer

# Encrypting Passwords in a .NET app.config File &laquo; Rams On It - .NET

Pingback from  Encrypting Passwords in a .NET app.config File &laquo; Rams On It - .NET

# convert html to wikipedia

Pingback from  convert html to wikipedia

Tuesday, May 13, 2008 7:17 AM by convert html to wikipedia

# Encrypting Passwords in a .NET app.config File

Your Story is Submitted - Trackback from DotNetShoutout

Thursday, November 20, 2008 7:49 AM by DotNetShoutout

# re: Encrypting Passwords in a .NET app.config File

Looks a nice solutions.

If only there were some way to do this on our legacy Solaris boxes.

Thursday, January 22, 2009 1:45 PM by RussellH

# re: Encrypting Passwords in a .NET app.config File

woow! dude, thats it a great post thanks for it

Saturday, March 07, 2009 4:49 PM by Jimmy

# re: Encrypting Passwords in a .NET app.config File

Cool, but you should note that the project may require adding a .NET reference to System.Security.dll before the enums (such as DataProtectionScope) will resolve correctly.

Wednesday, April 01, 2009 11:57 AM by MV10

# re: Encrypting Passwords in a .NET app.config File

Very nice this is something I wanted to do with my app.config.

I did notice that you can't read the SecureString on decrypt?

SecureString password = DecryptString(AppSettings.Password)

I did find so info on Marshal.SecureStringToBSTR which will convert it back to regular string after decryption?

Is this a good method or is there another way to decrypt back to a readable string?

Thanks

Monday, May 25, 2009 11:21 AM by David Welford-Costelloe

# re: Encrypting Passwords in a .NET app.config File

Sorru forgot to add the link to MSDN:

msdn.microsoft.com/.../system.runtime.interopservices.marshal(VS.71).aspx

Monday, May 25, 2009 11:25 AM by David Welford-Costelloe

# re: Encrypting Passwords in a .NET app.config File

I'm pretty new to VB.NET and I'm working on a desktop application. I need to encrypt some items in the userSettings and applicationSettings sections of the app.config file.

I successfully converted the example code to VB, but I have a question about implementing the code: Where do I put it? I have one form in my app. Will it just go in the code behind for the form, or does the code need to go in its own class? And if that's the case, how do I access it from my form?

If not the author, could SOMEone please help me?

Thanks!

Thursday, May 28, 2009 12:47 PM by MarkY

# re: Encrypting Passwords in a .NET app.config File

Use appropriate members of the System.Runtime.InteropServices..::.Marshal class, such as the SecureStringToBSTR method, to manipulate the value of a SecureString object.

Tuesday, June 16, 2009 9:42 AM by rrvolk

# re: Encrypting Passwords in a .NET app.config File

You can see he already does that in the ToInsecureString() method. To get the readable string do this: string readable = ToInsecureString(password);

Tuesday, June 16, 2009 9:58 AM by rrvolk

# re: Encrypting Passwords in a .NET app.config File

Just two small issues if it's not information set at runtime from the user such as a password, but pre-coded or preset value in the project's applications setting, such as connection strings:

- this secures the information in the app.config file, but, if you open the .exe file with notepad, the value will still be obvious in plain text.

- if the application is installed on the users machine, but not yet run, the information isn't encrypted yet and vulnerable.

Tuesday, October 20, 2009 1:05 PM by Brian

# re: Encrypting Passwords in a .NET app.config File

Informative post, but:

SecureString implements IDisposable... I guess, it is recommended to call it's Dispose Method when you're done with it... so imo...

using(var secure = new SecureString()) {

...

}

...should be the way to go.

Friday, February 05, 2010 2:04 PM by void

# re: Encrypting Passwords in a .NET app.config File

I know it is unlikely that this old post is still monitored, but in case ...

1) Can this technique be used if the configuration file is to be encrypted and decrypted by multiple users on the same machine? We have a common config file for an app we develop but one that gets used by 4 seperate accounts.

2) Can this technique be used at all if the configuration file is a non-standard configuration file? We use our own for legacy reasons.

Tuesday, May 04, 2010 4:43 PM by Keith Douglas

# re: Encrypting Passwords in a .NET app.config File

Cheers for this snippet - something nice and straight forward for my application.  Something to stop the casual browser from nicking the password and/or any other config stuff I don't want.

No point to this point other than: thanks - it helped me out!

Thursday, August 05, 2010 8:47 AM by Matt Blackler

# re: Encrypting Passwords in a .NET app.config File

Your solution do not work on IIS6, the DecryptString always return empty secure string. If I run asp.net solution on ASP.NET developer server, everything works fine. It seems some kind of permission issue?

I do not get any message in event viewer, also no error produced.

Do you know where problem could be?

Wednesday, September 01, 2010 10:43 AM by Tomas

# re: Encrypting Passwords in a .NET app.config File

I'm experiencing the same issue as Tomas... the DecryptString returns an empty value on the customer's test server, but works fine on my dev machine.  Odd...

Monday, October 04, 2010 11:46 AM by Dave

# re: Encrypting Passwords in a .NET app.config File

references required:

using System.Security;

using System.Security.Cryptography;

Friday, December 03, 2010 9:34 AM by ScottJ

# re: Encrypting Passwords in a .NET app.config File

When you encrypt something on machine A it's NOT possible to copy the project to machine B and decrypt it.

System.Security.Cryptography.DataProtectionScope.CurrentUser

Is the hint. It is possible to do it for different users on the same machine with

System.Security.Cryptography.DataProtectionScope.LocalMachine

but not for different machines.

As the link from Jon states (msdn.microsoft.com/.../ms995355.aspx) the users password and some other LOCAL stuff is used to do the encryption, these machine/users specific attributes are completely different on another machine, so decryption fails.

Thursday, March 10, 2011 6:54 AM by tikra

# re: Encrypting Passwords in a .NET app.config File

Thanks for a great explanation and code.

Wednesday, April 20, 2011 8:10 AM by Ronny Hermans

# re: Encrypting Passwords in a .NET app.config File

"Thanks for a great explanation and code." O_o ???

code contain errors, but explanation is very good

Thursday, April 28, 2011 5:37 AM by BOBO

# re: Encrypting Passwords in a .NET app.config File

very good, i made a class from your code and using it in all my projects where i need to encrypt the passwords

Saturday, May 07, 2011 2:07 PM by adeel

# re: Encrypting Passwords in a .NET app.config File

The Decrypt function needs a User Profile loaded to store the keys. So my implementation failed as i was decrypting using the SYSTEM context on a server. Is there any level of protection like this where you don;t need the user profile loaded to decrypt?

Friday, August 12, 2011 12:18 PM by Rob

# re: Encrypting Passwords in a .NET app.config File

I need to run my exe from a common network directory and several users will access it from the same network directory.

Is it possible to use a commom key so taht it works for all user when the executable is in network directory with the app.config file but user loged in from there machine

Thursday, August 18, 2011 2:49 PM by LR SCA NY

# re: Encrypting Passwords in a .NET app.config File

"When you encrypt something on machine A it's NOT possible to copy the project to machine B and decrypt it.

System.Security.Cryptography.DataProtectionScope.CurrentUser

Is the hint. It is possible to do it for different users on the same machine with

System.Security.Cryptography.DataProtectionScope.LocalMachine

but not for different machines.

"

This is BS..  How can I store a password encrypted in the app.config, but carry around the key in the source to decrypt it.  It has to be portable accross machines...?

Wednesday, December 21, 2011 7:43 PM by Gavin Stevens

# re: Encrypting Passwords in a .NET app.config File

Gavin,

Read the DPAPI docs. THe key is not required in the code. In fact the key is not stored at all. The random data used to generate the key is stored in a protected file in teh users' home folder

Wednesday, January 11, 2012 3:06 PM by Elijah

# re: Encrypting Passwords in a .NET app.config File

The code was a big help for me. Thanks.

Saturday, January 21, 2012 6:23 AM by Fateme

# re: Encrypting Passwords in a .NET app.config File

The decryption for me was actually:

string password = ToInsecureString(DecryptString(Properties.Settings.Default.EncryptedPassword));

Saturday, February 11, 2012 12:27 AM by nick

# re: Encrypting Passwords in a .NET app.config File

Great Article. The "Encrypting Strings with ProtectedData" worked magnificiently in my code. Thanks a ton.

Tuesday, May 15, 2012 3:33 AM by Abhishek Kashyap

# Windows Service application app.config | PHP Developer Resource

Pingback from  Windows Service application app.config | PHP Developer Resource

# re: Encrypting Passwords in a .NET app.config File

Great articale!!!!

Wednesday, June 20, 2012 7:43 AM by Nicolas

# Encrypting Sections of App.Config &laquo; BrainStorage

Pingback from  Encrypting Sections of App.Config &laquo; BrainStorage

Friday, December 28, 2012 3:53 PM by Encrypting Sections of App.Config « BrainStorage

# re: Encrypting Passwords in a .NET app.config File

This is working fine but it cannot be used if you encrpyt the password and you want to use the password over several machines with different users. Unfortunately there seems only the option to encrypt with CurrentUser or LocalMachine. If you want to decrypt with another machine or user it will not work.

Tuesday, January 29, 2013 7:08 AM by TobiasBrue

# re: Encrypting Passwords in a .NET app.config File

Pretty nice post. I just stumbled upon your blog and wanted to mention that I've really enjoyed browsing your blog posts. After all I'll be subscribing for your feed and

I hope you write once more soon!

Sunday, April 21, 2013 12:39 PM by Borges

# re: Encrypting Passwords in a .NET app.config File

hello amazing site

Friday, May 10, 2013 12:23 PM by qhnjncjh@gmail.com

# re: Encrypting Passwords in a .NET app.config File

You need to take part in a contest for one of the finest sites online. I will recommend this blog!

Thursday, May 16, 2013 12:45 PM by mfllbczc@gmail.com

Leave a Comment

(required) 
(required) 
(optional)
(required)