Click here to Skip to main content
11,704,315 members (46,288 online)
Click here to Skip to main content

Encypt and decrypt StorageFile in Windows Store apps

, 30 Apr 2013 CPOL 10.8K 3
Rate this:
Please Sign up or sign in to vote.
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. 

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.  

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)

Share

About the Author

Farhan Ghumra
Software Developer (Senior) Simform Solutions Pvt. Ltd.
India India
Windows Metro Store Apps Developer having 1+ year of experience

Follow me on: My Blog on Windows 8 | Twitter | Facebook | LinkedIn

Check Out My Articles & Tips on CodeProject

You may also be interested in...

Comments and Discussions

 
SuggestionMaybe a better way?? Pin
Michael Puckett II28-Aug-14 10:07
memberMichael Puckett II28-Aug-14 10:07 
GeneralRe: Maybe a better way?? Pin
Ahmed_Rashad5-Jan-15 1:05
memberAhmed_Rashad5-Jan-15 1:05 
QuestionGreat Article. Thank you. It was extremely helpful. I have a question if you know the answer... Pin
Michael Puckett II27-Aug-14 18:07
memberMichael Puckett II27-Aug-14 18:07 
Questionsqlite encryption Pin
Member 106175774-Apr-14 10:43
memberMember 106175774-Apr-14 10:43 
Questiondata protection provider string for all systems/tablets Pin
Member 84441467-Oct-13 1:38
memberMember 84441467-Oct-13 1:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150819.1 | Last Updated 30 Apr 2013
Article Copyright 2013 by Farhan Ghumra
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid