How to encrypt data for Windows Phone 8
[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]
This topic will show you how to encrypt and decrypt confidential data such as passwords, connection strings, and PINs in a Windows Phone app by using the Data Protection API (DPAPI).
Saving confidential data in a phone’s isolated storage is not secure. Encrypting the data will not increase the security if the decryption key resides on the phone, no matter how well the key is hidden. DPAPI solves the problem of explicitly generating and storing a cryptographic key by using the user and device credentials to encrypt and decrypt data. You can use the ProtectedData class that provides you access to DPAPI through Protect and Unprotect methods. You use the Protect method to encrypt the data and the Unprotect method to decrypt the data. On a Windows Phone device, every app gets its own decryption key, which is created when you run the app for the first time. Calls to Protect and Unprotect will implicitly use the decryption key and make sure that all the data remains private to the app. The key will also persist across updates to the app.
If you have a large amount of data to encrypt and if that data is stored in the local database for Windows Phone, encrypt the entire database, rather than encrypting individual pieces of data. To encrypt the entire database, use the Password parameter. For more information see, Local database connection strings for Windows Phone 8 topic.
In this procedure, you will create the app, encrypt the PIN by using the Protect method, store it in isolated storage, and then decrypt it by using the Unprotect method.
The Protect method takes in as parameters the data to encrypt and entropy information. Entropy information is an additional byte array that you can specify to increase the complexity of encryption. You can set it to null, for no additional complexity. In this topic, it is set to null. If you provide the entropy value when using the Protect method, you must also use this value when you decrypt the data when using the Unprotect method.
The Unprotect method takes in as parameters the data that was encrypted by using the Protect method and entropy information that was used to encrypt the data. The data and entropy parameters in Protect and Unprotect methods are of type Byte.
In Visual Studio, create a new project by selecting the File | New Project menu command.
The New Project window is displayed. Expand the Visual C# templates, and then select the Windows Phone templates.
Select the **Windows Phone App ** template. Fill in the Name box with a name of your choice.
Click OK. The Windows Phone platform selection dialog box is displayed.
In the Target Windows Phone OS Version menu, ensure that Windows Phone OS 7.1 is selected.
Click OK. A new project is created, and MainPage.xaml is opened in the Visual Studio designer window.
On MainPage.xaml, replace the grid named LayoutRoot with the following code. This code creates a TextBox control for entering the PIN and two buttons for storing and retrieving the PIN.
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock x:Name="ApplicationTitle" Text="Encryption Example" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock x:Name="PageTitle" Text="app login page" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition />
<RowDefinition Height="auto" />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Pin" Margin="10" />
<TextBox x:Name="TBPin" Height="75" Width="300" HorizontalAlignment="Left" Margin="83,22,0,44" Grid.Row="1" />
<Button x:Name="BtnStore" Content="Store" Grid.Row="1" Click="BtnStore_Click" Margin="-6,123,6,58" Grid.RowSpan="3" />
<Button x:Name="BtnRetrieve" Content="Retrieve" Grid.Row="3" Click="BtnRetrieve_Click" Margin="-6,111,6,72" Grid.RowSpan="2" />
</Grid>
</Grid>
Add the following using directives to the top of MainPage.xaml.cs.
using System.IO; using System.IO.IsolatedStorage; using System.Text; using System.Security.Cryptography;
Add the following line of code to the MainPage class to create a private string variable. This variable will be used later in the procedure when you store the PIN to isolated storage.
private string FilePath = "pinfile";
Add the following code to the MainPage class to create the BtnStore_Click event handler. This code converts the PIN to a Byte, encrypts it by using the Protect method, and then stores it in isolated storage by using the private method WritePinToFile().
private void BtnStore_Click(object sender, RoutedEventArgs e) { // Convert the PIN to a byte[]. byte[] PinByte = Encoding.UTF8.GetBytes(TBPin.Text); // Encrypt the PIN by using the Protect() method. byte[] ProtectedPinByte = ProtectedData.Protect(PinByte, null); // Store the encrypted PIN in isolated storage. this.WritePinToFile(ProtectedPinByte); TBPin.Text = ""; }
Add the following code to the MainPage class to create a private method named WritePinToFile(). This method takes in as a parameter the encrypted PIN of type Byte. It then stores the PIN in a file in the app’s isolated storage.
private void WritePinToFile(byte[] pinData) { // Create a file in the application's isolated storage. IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication(); IsolatedStorageFileStream writestream = new IsolatedStorageFileStream(FilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write, file); // Write pinData to the file. Stream writer = new StreamWriter(writestream).BaseStream; writer.Write(pinData, 0, pinData.Length); writer.Close(); writestream.Close(); }
Add the following code to the MainPage class to create the BtnRetrieve_Click event handler. This code retrieves the PIN from isolated storage, decrypts it by using the Unprotect method and converts it into a string. The PIN is then displayed in the text box. The process of retrieving the PIN from isolated storage is implemented in a private method named ReadPinFromFile().
private void BtnRetrieve_Click(object sender, RoutedEventArgs e) { // Retrieve the PIN from isolated storage. byte[] ProtectedPinByte = this.ReadPinFromFile(); // Decrypt the PIN by using the Unprotect method. byte[] PinByte = ProtectedData.Unprotect(ProtectedPinByte, null); // Convert the PIN from byte to string and display it in the text box. TBPin.Text = Encoding.UTF8.GetString(PinByte, 0, PinByte.Length); }
Add the following code to MainPage class to create a private method named ReadPinFromFile(). This method accesses the file that was created in the WritePinToFile() method and reads the PIN from that file.
private byte[] ReadPinFromFile() { // Access the file in the application's isolated storage. IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication(); IsolatedStorageFileStream readstream = new IsolatedStorageFileStream(FilePath, System.IO.FileMode.Open, FileAccess.Read, file); // Read the PIN from the file. Stream reader = new StreamReader(readstream).BaseStream; byte[] pinArray = new byte[reader.Length]; reader.Read(pinArray, 0, pinArray.Length); reader.Close(); readstream.Close(); return pinArray; }