LANGUAGES: All .NET Languages
ASP.NET VERSIONS: 1.0 | 1.1
Exploring the DPAPI
By Don Kiely
The Windows Data Protection API (DPAPI) solves a gnarly problem you face anytime you need to encrypt data: Where do you store the keys? As I've discussed in past installments in this series, DPAPI uses features built into Windows since Windows 2000 to save keys securely within Windows itself, under a robust layer of keys based on authentication credentials.
But while DPAPI provides measures to protect data, it is a Win32 API and has a few options that can make it less than intuitive. To start, it consists of two interfaces, user and system. Frankly, I've no idea why Microsoft chose to even document the system interfaces, as they are usable only by the Local Security Authority (LSA) to perform the actual encryption; your code must use the user interface. This interface is included in crypt32.dll provided by Windows.
The good news is that there are only two methods in the interface, CryptProtectData and CryptUnprotectData, each of which returns true if the call was successful. You can use the optional CRYPTPROTECT_PROMPSTRUCT structure to prompt the user for a password, and use the DATA_BLOB structure to receive the encrypted data or to pass it to be decrypted. The latter is an opaque structure that, according to the documentation, you only need to store without paying any attention to the internals for any reason. The contents are hashed with a Hashed Message Authentication Code (HMAC), using the SHA-1 hashing algorithm.
The CryptProtectData method has several parameters:
- a reference to DATA_BLOB structure with clear text to be encrypted
- an optional description of the data to be encrypted, which is included in the protected data
- an optional entry in the form of a reference to another DATA_BLOB, used to salt the encryption, kind of a second password that can be application- or instance-specific
- a reserved parameter
- an optional reference to CRYPTPROTECT_PROMPTSTRUCT
- several optional defined flags to indicate which data store to use, whether to use a user interface to prompt the user for required information, whether to generate an audit through the LSA, and whether to bypass encryption and only query the MasterKeys and re-encrypt them in memory
The result is an output reference to the DATA_BLOB with the protected data, which you can store wherever you want knowing that it would be very difficult for a hacker to crack. The CryptUnprotectData method has pretty much the same set of parameters, but is geared toward output of the encrypted data.
The hardest thing about using DPAPI is that the methods are Win32 API functions, which require that the data be in precisely the right data types, or else the call will fail. This usually means that you have to write a hundred lines of code to get the data in the right form to make a single statement call to the API, particularly if you use a language with non-standard native data types. If you're writing .NET code, this means some messy p/invoke calls to unmanaged code, which are never easy or fun, and are fraught with potential security issues.
Fortunately, Microsoft has made available a wrapper class written in both VB .NET and C# that does most of the heavy lifting for you. It won't solve any security problems, but it makes using DPAPI just about as easy as it should be. The components are available at http://www.gotdotnet.com, a Microsoft site with lots of sample code, discussions, and workspaces for development projects. Go there, select User Samples from the Toolbox, and search for DPAPI. It includes the source code, so you can learn a lot about DPAPI by going through the code. I showed an example of using this component in an earlier installment of this column.
Next time I'll wrap up my DPAPI rants by discussing some of the hoops you need to jump through to use it with ASP.NET, particularly if you want to use the user store for the keys.
Don Kiely is senior technology consultant for Information Insights, a business and technology consultancy in Fairbanks, Alaska. E-mail him at mailto:[email protected].