Project Description

.Net portable password management made easy!

A key storage class library based on DPAPI? Why not an easy portable key storage framework to be used with Microsoft .Net 2.0 and Mono 2.0 on any platform?

Currently supports:

  • DPAPI on Windows
  • Keychain Services API on Mac OS X
  • GNOME-Keyring on Linux

Follow alexpilotti on Twitter

Introduction

The idea behind this project is to create a simple open source framework for a transparent portable key storage management in .Net, targetting .Net Framework 2.0 and Mono 2.0.

Many applications (web browsers, email clients, web applications, network connettivity tools, to name a few) need a way to save and retrieve passwords, connection strings and other secrets (commonly called keys in this context), based on the user's profile.
It should not be possible for other users (and in some cases for other applications) to retrieve the stored secrets. This feature is accomplished through standard cryptographic solutions. The big challenge is how to securely store the decryption key needed to decrypt the data when the application needs to retrieve it.

Please note that this kind of technology, although suitable for managing passwords and other similar secrets, is not suitable for more complex scenarios, requiring a stronger degree of privacy.

Well if this seems a limit for you, start thinking on a suitable way of securely store encryption keys without having to ask the user for a password (or smart card, fingerprints, retinal scans, etc.) and you will probably end up with a solution similar to those discussed here. If not, you're probably the next crypto hero :-)

Each platform (MS Windows, Linux, Mac OS X, etc.) provides a solution for solving this problem:

  • MS Windows: Data Protection API (DPAPI)
  • Mac OS X: Keychain Services API
  • Linux GNOME: gnome-keyring-manager
  • Linux KDE: kwallet


Wouldn't it be nice to have a single simple framework to handle password storage without having to care on which platform your app is currently running on?

How does it work?

Enough theory by now! Here's the code:

// get the a provider instance for the current platform
IKeyStorageProvider provider = KeyStorageManager.GetProvider();


// Store a key
provider.StoreKey("key1", "thebigsecret");


// Retrieve a key
string secret = provider.RetrieveKeyAsString("key1");


// Delete a key
provider.DeleteKey("key1");


Just reference KeyStoragemanager.dll among your project references.

As you can see, it is really easy. Storing, retrieving and deleting keys is easy and you don't have to bother thinking about the platform your app is running on.


Ok, but what if the secret data is not a string? Here we go:

byte [] secret = Encoding.UTF8.GetBytes("theotherbigsecret");


// Store a key
provider.StoreKey("key2", secret);


// Retrieve a key
secret = provider.RetrieveKey("key2");


That's it! More overloads can be added as needed, e.g. to handle object serialization.

If you're interested in a simple use of this class library, you don't need to read any further.

You can use it in any kind of app, even web apps. On Windows there's no problem at all, but please note that on Linux and Mac OS X user interaction might be required to unlock the key containers!

Before digging into the details, here's the class diagram:

KeyStorageClassDiagram.png

For the architecturally minded, basically it implements an Abstract factory pattern along with an Adapter pattern for each implemented platform. Back to the code, that's enough with it. :-)

For each platform, at least two classes need to be implemented:

  • IKeyStorageProviderManager: needed to check for the availability of the implemented technology on the current platform and for getting an instance of the related IKeyStorageProvider.
  • IKeyStorageProvider: the provider / adapter. Here's where most of the code goes.


Each IKeyStorageProvider, implementing class might also provide methods and properties specific to the implementation.

Finally, KeyStorageProvider is a factory with a static method to return a new instance of IKeyStorageProvider suitable for the platform where the calling app is running on.

Ok, now to go on with this subject we need to inroduce each platform!

Data Protection API

On MS Windows 2000 and Windows CE 4.0, a specific API is available: two functions CryptProtectData/CryptUnprotectData, commonly called DPAPI. For details see: http://msdn.microsoft.com/en-us/library/ms995355.aspx.

This API is used broadly in the Windows OS, for example by Internet Explorer and Windows Explorer's network password storage.

This API does not provide a way to store the encrypted data. It just provides a way to transparently encrypt and decrypt data, without the need of an encryption key. The key is stored in the user profile, encrypted with data derivated, among other things, from the user's password. If an administrator resets the user's password the encryption key changes and previously encrypted data becomes unrecoverable!

How secure is this?

Pros:

  • No need to manage encryption keys
  • An optional entropy can be provided (an additional application defined key, in simple terms)
  • If accessed by resetting the user's password (e.g. on a stolen computer), the data becomes unrecoverable


Cons:

  • Any application running with the user's credentials is able to decrypt the data
  • Although not easy, an ad hoc kernel driver could retrieve the DPAPI encryption key


Note: the latter is not really a "cons", as having administrative/root access can compromise the security on any machine, one way or the other.

Data Protection API implementation

DPAPIKeyStorageProvider is the class implementing the IKeyStorageProvider interface. The class handles encryption and decryption. It is marked as abstract in order to leave the actual storage handling to any subclass.

As already stated, DPAPI don't provide a way to store the encrypted data. Data can be stored anywhere, as there's no way to get the clear text back without the correct decryption key.
This framework provides am XML file based solution (DPAPIXmlKeyStorageProvider), but a different one based on the Windows Registry or a database can be easily provided by subclassing DPAPIKeyStorageProvider.

DPAPIXmlKeyStorageProvider stores the data in a file called KeyStorage.xml in the local application data directory (e.g.: c:\Users\username\AppData\Local\KeyStorage.xml on Vista). This can be changed with the KeyStorageXmlPath property.

Please note that the XML is validated against an XSD schema which is embedded in the assembly. Please see the snapshot below for a look at the document structure. Encrypted data is simply encoded with Base64.

DPAPIKeyStorageProvider provides three abstract methods (pure virtual, in C++ terms) to be implemented in subclasses:

protected abstract void StoreData(string name, byte [] secret);
protected abstract byte[] LoadData(string name);
protected abstract bool DeleteData(string name);


Those methods just store, return and delete the encrypted data. As already stated the encryption/decryption process is left to the base class and is independent from the chosen storage.

What about the DPAPI function calls? This is just a matter of P/Invoke. I provided a wrapper assembly here, simply called DPAPIWrapper.dll (the name is not that original, but at least you know what it is for :-) ). Sources are also available here. Please note that there are plenty of similar wrappers on the web. There's also one available on MS Patterns & Practices.

If you want to use the DPAPIWrapper in your .Net apps, just call the following static methods, or one of the simpler overloads, from the AlexPilotti.DPAPI.DPAPIWrapper class.

public static byte[] Encrypt(byte[] plainText, byte[] optionalEntropy, Store store);
public static byte[] Decrypt(byte[] cipherText, byte[] optionalEntropy, Store store);


KeyStorageXml.png

GNOME-keyring

This is GNOME's solution for key management, available on Linux and other GNOME supported platforms. On Linux there's also kwallet, from the KDE environment, which has not yet been added to this framework.

A keyring is a key (secrets) container. Two keyrings (login and session) are available by default, but others can be created as needed. The design is similar to Mac OS X Keychain Services, also discussed here.
The session keyring is non persistent, this means that data will be lost when the session ends.

This solution is based on a user space daemon (called gnome-keyring-daemon). When a user or application wants to access a key inside a keyring, a password must be provided to unlock the latter. A PAM module (libpam-gnome-keyring) is available in order to unlock automatically keyrings at login and when exiting the screen saver. In order for this to work a keyring must have the same password as the user's login.

If the user's login password changes, after the next logon a password needs to be provided to manually unlock a keyring. Although maybe a bit annoying, this is really safe, as there's no way for someone not knowing your password to access your stored keys!

Persistent keyrings are stored in the user home under: ~/.gnome2/keyrings/

The related API reference is available here: http://library.gnome.org/devel/gnome-keyring/
and a CLI implemenentation is available here: here: http://andrew.jorgensenfamily.us/2008/08/gnome-keyring-sharp/, which has been used in this project.
Thanks to Andrew Jorgensen for saving me the time to P/Invoke the C API. :-)

There's also a gnome-keyring-manager to graphically manage your keyrings. In case it should not be available as a packaged binary on your Linux distro, the sources are available here: http://ftp.acc.umu.se/pub/gnome/sources/gnome-keyring-manager/. Just run ./configure and make install to compile and install.

Alternatively a GNOME application called seahorse is available. This app is also able to change a keyring's password, useful in case it got out of sync with the user's password, which is still a problem when the user's password is changed.

Please note: gnome-keyring-daemon is not started automatically on a command line login (e.g via SSH).


The gnome-keyring-manager:

gnome-keyring-manager.png

GNOME-keyring implementation

The adapter class implementing the GNOME features is called GnomeKeyringProvider.cs.

By default the default (login) keyring is employed as a container. This can be changed by setting the Keyring property. Use "session" to employ a non persistent keyring.

As already stated we are using a managed class to access the service, so there's no need for P/Invoke.

// To store a secret:
Ring.CreateItem(Keyring, ItemType.GenericSecret, name, tbl, secret, true);

 

// To retrieve a secret:
Ring.Find(ItemType.GenericSecret, tbl))


Please refer to the class library sources for more details.

Mac OS X Keychain Services API

Mac OS X includes a technology called Keychain Services API to do the job.

A Keychain is a container of keys (passwords, certificates, text, etc). A keychain called login is available by default for each user. An application is free to create as many keychains as desired.
Keychains are protected by a password through encryption. If a keychain's password matches the user password, the keychain is unlocked at login. Otherwise it must be unlocked manually. Once unlocked, the contained keys are accessible by any application in the current user session (executed with the user's credentials).

What happens to a keychain automatically unlocked at login if the user's login password is changed?

  • If it's changed by the user via the "System Preferences" -> "Accounts" UI, the keychain's password is kept in sync.
  • If it's changed via "passwd" or reset by an administrator, *the keychain password will not be changed+.


This means that if someone stoles your MacBook, changes your password and does a login with your username, there's no way to retrieve your keys!
This happens of course if the auto logon feature is off (i.e. the user provides a password to login).

User keychains are stored under ~/Library/Keychains/

What about the programming model?

The API is documented here: http://developer.apple.com/documentation/Security/Conceptual/keychainServConcepts/keychainServConcepts.pdf

The API are written in C and are part of the Security framework and thus easily available to our managed code via P/Invoke.

Keychains can be easily accesses with the Keychain Access UI, available in the standard Utilities folder:

MacOSX_Keychain.png

Mac OS X Keychain Services API Implementation

MacOSXKeychainProvider implements the desired service features.

Currently only the default keychain (login) is supported, but adding support for selecting a different Keychain is not a big issue.

The class includes the required P/Invoke external methods to access the Keychain services API.

Please note that the API are part of a framewok. In Mac OS X, a framework is a shared library along with headers, resources, versioning and more.
The problem is that Mono is not able to look in the default path for the library name referred in the DllImportAttribute.
That's why we provide the full path to the shared library: "/System/Library/Frameworks/Security.framework/Security"

The KeyStorageUtility command line app

This is a simple app used to test the features discussed above. Its job is to store, retrieve and delete secrets using the KeyStorageManager framework.

The command usage is really simple:

KeyStorageUtility version 1.0
Copyright (C) Alessandro Pilotti 2009

http://www.codeplex.com/KeyStorage
info@pilotti.it

This is free software, you may use it under the terms of
the MIT license <http://www.codeplex.com/KeyStorage/license>

USAGE:

* To store a key:
KeyStorageUtility -s <name> <value>

* To retrieve a key value:
KeyStorageUtility -r <name>

* To delete a key:
KeyStorageUtility -d <name>



Conclusion

Well, that's it, by now. For any suggestion, I'll be glad to meet you on the Discussions page!



Alessandro Pilotti

Last edited Oct 31, 2012 at 9:44 AM by alexp, version 19