Using DPAPI with IsolatedStorage In Windows Phone 7 Mango Release
I was doing some work on the Mango release of Windows Phone 7 the other day. One of the great features (there are many) that has been added is support for DPAPI. One of the cases in which you might want to use this is to encrypt some content before storing it locally. In WP7, when an application stores data locally it uses something called IsolatedStorage. The IsolatedStorage system has some nice classes to help your applications read and write to it. One thing that I've discovered though (at least at this point) is that it fundamentally doesn't really work with content that's enrypted by DPAPI. Let me explain what I mean by that.
Supposed you use DPAPI to encrypt some content and then write it to disk. Now you want to read that encrypted data back in, decrypt it, and do something with it. Well if you follow most of the IsolatedStorage examples you will do something like:
//get into isolated storage for the credentials
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
{
//stream in our registration file
using (var stream = new
IsolatedStorageFileStream(REG_INFO_FILE, FileMode.Open, FileAccess.Read, store))
{
//read the contents into a variable
using (var reader = new StreamReader(stream))
{
//create and fill the byte array with the raw data so you can use it
byte[] rawData = new byte[reader.Length];
reader.Read(rawData, 0, Convert.ToInt16(byteStream.Length));
//now decrypt it
byte[] safeData = ProtectedData.Unprotect(rawData, null);
}
}
}
The problem is when you call Unprotect you will get an error along the lines of padding having been added. The problem is some extra characters that the default IsolatedStorageFileStream reader adds when it reads content in for you. To work around this problem, you need to get a reference to the underlying stream and read directly from it. For example, this code:
//create and fill the byte array with the raw data so you can use it
byte[] rawData = new byte[reader.Length];
reader.Read(rawData, 0, Convert.ToInt16(byteStream.Length));
Should be changed like this:
Stream byteStream = reader.BaseStream;
//create and fill the byte array with the raw data so you can use it
byte[] rawData = new byte[byteStream.Length];
byteStream.Read(rawData, 0, Convert.ToInt16(byteStream.Length));
//now decrypt it
byte[] safeData = ProtectedData.Unprotect(rawData, null);
Once you start using the BaseStream that should cure any padding errors.
Comments
Anonymous
January 01, 2003
The comment has been removedAnonymous
March 29, 2012
Hi Steve, I have a question regarding the storage of the user credentials in the IsolatedStorage. Will this approach pass the ACE reviews and security aspects?Anonymous
September 18, 2014
The comment has been removed