Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / security / encryption

Encypt and decrypt StorageFile in Windows Store apps

5.00/5 (2 votes)
30 Apr 2013CPOL2 min read 40.3K  
Encypt and decrypt StorageFile in Windows Store apps.

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. 

C#
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)
{
    // Create a DataProtectionProvider object for the specified descriptor.
    DataProtectionProvider Provider = new DataProtectionProvider(descriptor);

    // Create a random access stream to contain the plaintext message.
    InMemoryRandomAccessStream inputData = new InMemoryRandomAccessStream();

    // Create a random access stream to contain the encrypted message.
    InMemoryRandomAccessStream protectedData = new InMemoryRandomAccessStream();

    // Retrieve an IOutputStream object and fill it with the input (plaintext) data.
    IOutputStream outputStream = inputData.GetOutputStreamAt(0);
    DataWriter writer = new DataWriter(outputStream);
    writer.WriteBuffer(buffMsg);
    await writer.StoreAsync();
    await outputStream.FlushAsync();

    // Retrieve an IInputStream object from which you can read the input data.
    IInputStream source = inputData.GetInputStreamAt(0);

    // Retrieve an IOutputStream object and fill it with encrypted data.
    IOutputStream dest = protectedData.GetOutputStreamAt(0);
    await Provider.ProtectStreamAsync(source, dest);
    await dest.FlushAsync();

    //Verify that the protected data does not match the original
    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 the encrypted 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.  

C#
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)
{
    // Create a DataProtectionProvider object.
    DataProtectionProvider Provider = new DataProtectionProvider();

    // Create a random access stream to contain the encrypted message.
    InMemoryRandomAccessStream inputData = new InMemoryRandomAccessStream();

    // Create a random access stream to contain the decrypted data.
    InMemoryRandomAccessStream unprotectedData = new InMemoryRandomAccessStream();

    // Retrieve an IOutputStream object and fill it with the input (encrypted) data.
    IOutputStream outputStream = inputData.GetOutputStreamAt(0);
    DataWriter writer = new DataWriter(outputStream);
    writer.WriteBuffer(buffProtected);
    await writer.StoreAsync();
    await outputStream.FlushAsync();

    // Retrieve an IInputStream object from which you can read the input (encrypted) data.
    IInputStream source = inputData.GetInputStreamAt(0);

    // Retrieve an IOutputStream object and fill it with decrypted data.
    IOutputStream dest = unprotectedData.GetOutputStreamAt(0);
    await Provider.UnprotectStreamAsync(source, dest);
    await dest.FlushAsync();

    // Write the decrypted data to an IBuffer object.
    DataReader reader2 = new DataReader(unprotectedData.GetInputStreamAt(0));
    await reader2.LoadAsync((uint)unprotectedData.Size);
    IBuffer buffUnprotectedData = reader2.ReadBuffer((uint)unprotectedData.Size);

    // Return the decrypted data.
    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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)