Currently, I’m working on a product I call Alluvial, which aims to be a SQL Management Studio-like program for use with the Azure cloud’s SQL Services platform. While designing the initial login screen, I decided to implement a check box the user could click on labeled “Remember my password”, which (like SQL Management Studio), would remember the username:password between sessions.

When I actually got to implementing this feature, I faced various classic problems that, due to my young years, have not encountered before. The primary problem was: in order to “remember” a set of credentials, one would have to store it somewhere for later retrieval. This is bad, because as soon as credentials get written to disk, even if they are encrypted, you are entering very dangerous waters.

Eventually, I figured out and implemented what I believe to be a secure solution. I’ve created various security libraries you can check out on my source repository; in one of them is a new CloudCredentials class, which provides the developer with secure credentials that can be persisted and used with accessing Azure Cloud Services. I achieved this through the use of the unmanaged Data Protection and Windows Credential Management API’s.

Please read on for some more details.

I. Introduction

Normally when we need to store any password related data to disk, we do some in the form of a hash so we can authenticate the user in the future. A “Remember my Password” option requires more than just storing a hash, however.?This is compounded by the fact that the actual authentication doesn’t occur on the client’s side, but by some unknown entity out there in the cloud.

Obviously, storing the credentials anywhere on the machine opens up a gigantic security hole. Even if it is stored in?some secluded, guarded-by-strict-permissions, hive in the registry, you are just using a cheap form of security by obfuscation. Soon you will realize there is actually no perfect solution for this; you can’t make something invisible on your machine (that only you can see!). Credential management in general will never be 100% secure, unless you can get cooperation from the server through some sort of alternative identification that relies on some sort of intrinsic of the client machine.

But don’t look sad, nothing is perfect, but we can still strive to get as close to 100% as possible. And I believe I have a way that is pretty damn close. To recap, there are three things we need to satisfy in order to provide secure credentials management:

  1. A secure password
  2. A secure method of storing the password
  3. A secure method of retrieving the password

The credential type that Alluvial will be using, CloudCredentials, can be found in Omniscientist.Security.Authentication.dll, and it satisfies all three of these items. It derives its functionality from the Omniscientist.Security.Authentication.dll and Omniscientist.Security.Encryption.dll assemblies; so check those out if you want to create your own credentials type as well.

We’ll now go over how exactly the CloudCredentials type satisfies the above three points.

II. Secure Passwords

Before storage and retrieval can even be pondered upon, we need to start with a secure way of handling the password itself. Although we’ll be covering this in a bit: the storage and retrieval is made possible through the use of the Windows Credential Manager API, but that in itself is not enough.? If the client machine has been compromised by some sort of malware, there is nothing stopping a smart enough malware from retrieving user credentials from the user’s credential set via the same API. That’s why I have the password encrypted before being stored, and that encryption is what we’ll be focusing on first.

Encryption is a broad topic, but one promising way of achieving this that I stumbled upon was Microsoft’s own unmanaged Data Protection API. It’s a very simple API that allows you to encrypt and decrypt string values with an entropy that can be optionally provided.

So, it would seem that this aspect of the security all relies on the security of the entropy being used. While this may be true to a certain point, the DPAPI offers several other benefits from its use which offer additional security. Anything encrypted via the DPAPI can only be decrypted by the same user on the same machine. So, even if the user is legit, switching machines will result in being unable to decrypt any stored credentials. That shouldn’t be a big deal, as only a malicious individual would try to move any locally stored user credentials anyway. The data is encrypted using the Triple-DES algorithm, and user or machine specific keys may be used.

Your data may be potentially compromised if your machine is compromised, but only if the malicious agent can access and use the identity used to initially encrypt the data.

Using the DPAPI from managed-land requires some P/Invoke, you can view this in the NativeMethods.cs file that is part of the Omniscientist.Security.Encryption project, (Due to loss of old server, source is unavailable ATM.).

In the CloudCredentials object code, we encrypt/decrypt our passwords like so:

string secret =
    DPApi.Encrypt(_solutionPassword, KeyType.UserKey, _entropy);

Now, onto the secure storage and retrieval of the credentials, which is really the harder problem here.

III. Secure Storage of Passwords

If we’re already on a closed system, might as well make use of some closed and poor documented API’s!

The secure storage and retrieval of user credentials is achieve via the use of the unmanaged Windows Credential Management API. This is a secure (but not 100% so) way of storing credential information; it doesn’t end up being written to some easily-accessible location on the machine. If the attacker was aware of the Credential Management internals (something which could only be achieved via reverse engineering or just access to its source code), then I suppose that your data could be compromised. There are currently no known methods (that I could find in a brief search), of doing this, so you should consider your data safe.

Another important thing here is that you are using Microsoft’s security model, something that other Microsoft applications use. This, by default, makes it more secure than any sort of secure storage we can brew up (unless we’re patching the kernel or something ridiculous in the process), and (if a flaw is discovered that compromises the model’s security), then it would be Microsoft’s responsibility to fix it. Now, no one likes not having control over things, but you can believe that that would receive some immediate attention from Microsoft, as that would be a big deal.

If your application requires absolute, 100% (well, 99.999999%), military-grade security, you would not be using Windows anyway.

To use the Windows Credential Management API from managed-land, some very tricky interop is required. Luckily, you can see how this is done by peering over the NativeMethods.cs and CredentialHandle.cs files which belong to the Omniscientist.Security.Authentication.dll assembly (Due to loss of old server, source is unavailable ATM. Links are hidden until code is restored.).

The unmanaged calls we need to make are to CredRead, CredWrite, and CredFree, which all make use of the CREDENTIAL structure.

The CloudCredentials object type does not need to bother with manually calling these, however, and neither will you if you seek to extend the library. The code in CloudCredentials that stores the credential information is as follows:

int writeRetVal;

if ((writeRetVal = CredentialHandle.WriteCredential(
        String.Format(CultureInfo.InvariantCulture, "{0}:{1}",
            _authorityName,
            _solutionName),
        secret))
    != 0)
    {
        throw new OmniSecurityException(
            String.Format(CultureInfo.CurrentCulture, "... {0}", writeRetVal));
    }

Excellent…now, the last thing on the list is to be able to securely retrieve the credentials.

IV. Secure Retrieval of Passwords

In order to retrieve our stored credentials, we once again make use of the Windows Credential Management API. Please refer to “III. Secure Storage of Passwords” to get most of the details.

The CloudCredentials object type uses the following code to retrieve the stored credential information:

//Do some checks to ensure none of the required fields are null, and then:
string secret = CredentialHandle.ReadCredential(
                        String.Format(CultureInfo.InvariantCulture, "{0}:{1}",
                            _authorityName,
                            _solutionName));

_solutionPassword = DPApi.Decrypt(secret, entropy);

?

And that’s that. The above gives you a pretty solid way of being able to “remember” supplied user credentials for Cloud authentication. Of course, the really interesting code is in how we actually implement that DPApi and CredMan functionality and interop; but I’m not going to spend time posting that here when you can easily just browse my source for it.

All in all, the Omniscientist.Security namespace is very young and new, (like, maybe a day old from when this was posted), so don’t expect everything to be amazingly perfect, there’s always room for a redesign in the future in order to achieve even more elegant looking code.

Browse the Omniscientist.Security source here: (Due to loss of old server, source is unavailable ATM. Links are hidden until code is restored.)

Enjoy.

Matt Weber

I'm the founder of Bad Echo LLC, which offers consulting services to clients who need an expert in C#, WPF, Outlook, and other advanced .NET related areas. I enjoy well-designed code, independent thought, and the application of rationality in general. You can reach me at matt@badecho.com.

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 
   
© 2012-2013 Matt Weber. All Rights Reserved. Terms of Use.