Introduction
I was developing an app for secure storage of documents. I searched MSDN and Stack Overflow to know about encryption APIs available in WinRT. I didn't find any sample or easy code snipped which explains the way to encrypt/decrypt the StorageFile.
After lot of trial-and-error, I managed to create a sample app for storing files in secure way.
Background
First of all let me share you the something about cryptography APIs available in WinRT. WinRT has total 9 namespace for security & for cryptography there's 4 namespace. The below list shows the MSDN document links to each of namespace.
But for us, we have goal of securing files, so we will use Windows.Security.Cryptography.DataProtection
namespace. It has single class DataProtectionProvider. It has methods to asynchronously encrypt and decrypt static data or a data stream. It has two constructor, one for encryption and second for decryption. To encrypt the data, data protection descriptors are begin used. It is used to define the way of protecting the data. I would recommend to read these two documents to know more about protection descriptor.
Using the code
This sample is heavily influenced from MSDN document and CryptoWinRT sample. The new thing in my article is just easiness to encypt/decypt StorageFile
. First of all user will pick the file to encrypt it. The chosen StorageFile
is read saved to IBuffer
. Then the custom method is being called with IBuffer
and security descriptor. The method returns the encypted data as IBuffer
. Then the buffer data is written over StorageFile
, so that StorageFile
become encypted and it can't be open just by "double clicking" on it.
private async void DoEncrypt_Click(object sender, RoutedEventArgs e)
{
IBuffer data = await FileIO.ReadBufferAsync(FileForEncryption);
IBuffer SecuredData = await SampleDataProtectionStream("LOCAL = user", data);
EncryptedFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(
"EncryptedFile" + FileForEncryption.FileType, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBufferAsync(EncryptedFile, SecuredData);
txtResult.Text += "File encryption successfull. File stored at " + EncryptedFile.Path + "\n\n";
}
public async Task<IBuffer> SampleDataProtectionStream(String descriptor, IBuffer buffMsg)
{
DataProtectionProvider Provider = new DataProtectionProvider(descriptor);
InMemoryRandomAccessStream inputData = new InMemoryRandomAccessStream();
InMemoryRandomAccessStream protectedData = new InMemoryRandomAccessStream();
IOutputStream outputStream = inputData.GetOutputStreamAt(0);
DataWriter writer = new DataWriter(outputStream);
writer.WriteBuffer(buffMsg);
await writer.StoreAsync();
await outputStream.FlushAsync();
IInputStream source = inputData.GetInputStreamAt(0);
IOutputStream dest = protectedData.GetOutputStreamAt(0);
await Provider.ProtectStreamAsync(source, dest);
await dest.FlushAsync();
DataReader reader1 = new DataReader(inputData.GetInputStreamAt(0));
DataReader reader2 = new DataReader(protectedData.GetInputStreamAt(0));
await reader1.LoadAsync((uint)inputData.Size);
await reader2.LoadAsync((uint)protectedData.Size);
IBuffer buffOriginalData = reader1.ReadBuffer((uint)inputData.Size);
IBuffer buffProtectedData = reader2.ReadBuffer((uint)protectedData.Size);
if (CryptographicBuffer.Compare(buffOriginalData, buffProtectedData))
{
throw new Exception("ProtectStreamAsync returned unprotected data");
}
return buffProtectedData;
}
Similarly to decrypt the encrypted file, user will first choose the file, then it is read to IBuffer
. The custom method decrypt the data and returns IBuffer
. Then the data is written to StorageFile
.
private async void DoDecrypt_Click(object sender, RoutedEventArgs e)
{
IBuffer data = await FileIO.ReadBufferAsync(EncryptedFile);
IBuffer UnSecuredData = await SampleDataUnprotectStream(data);
DecryptedFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync(
"DecryptedFile" + FileForEncryption.FileType, CreationCollisionOption.ReplaceExisting);
await FileIO.WriteBufferAsync(DecryptedFile, UnSecuredData);
txtResult.Text += "File decryption successfull. File stored at " + DecryptedFile.Path + "\n\n";
}
public async Task<IBuffer> SampleDataUnprotectStream(IBuffer buffProtected)
{
DataProtectionProvider Provider = new DataProtectionProvider();
InMemoryRandomAccessStream inputData = new InMemoryRandomAccessStream();
InMemoryRandomAccessStream unprotectedData = new InMemoryRandomAccessStream();
IOutputStream outputStream = inputData.GetOutputStreamAt(0);
DataWriter writer = new DataWriter(outputStream);
writer.WriteBuffer(buffProtected);
await writer.StoreAsync();
await outputStream.FlushAsync();
IInputStream source = inputData.GetInputStreamAt(0);
IOutputStream dest = unprotectedData.GetOutputStreamAt(0);
await Provider.UnprotectStreamAsync(source, dest);
await dest.FlushAsync();
DataReader reader2 = new DataReader(unprotectedData.GetInputStreamAt(0));
await reader2.LoadAsync((uint)unprotectedData.Size);
IBuffer buffUnprotectedData = reader2.ReadBuffer((uint)unprotectedData.Size);
return buffUnprotectedData;
}
Points of Interest
It this way, encryption & decryption is too easy in WinRT. But lack of good articles and confusing MSDN document one has to bear more to search. I have provided simple app to secure StorageFile
. MSDN uses term "Stream Data", but novice developer will definitely search for StorageFile