A mobile device no matter
what operating system or platform is inherently insecure. A mobile
device is not locked safely in a server room within a secure data center
like a web server. A mobile device is easily misplaced or stolen. For
just about any computing platform, loss of physical control is loss of
security. Therefore, it is important to minimize storing sensitive data
on a mobile device.
However, there are scenarios in which it is
convenient to store sensitive data on a device. As an example, a user
would never use a video player application that requires the user to
memorize and enter a long key to unlock DRM'd content. It is a risk
management challenge that weighs the benefits and inconvenience provided
by any given security solution. This section in the MSDN documentation
provides a detailed overview of balancing security with convenience:
http://msdn.microsoft.com/en-us/library/ff402533(v=VS.92).aspx
In the next few sections, I provide an overview of the capabilities available in the Windows Phone 7 platform.
1. Secure Sockets Layer
Many mobile applications transfer data to and from
the server-side of a mobile application solution. In cases where
sensitive data must be transported always use Secure Sockets Layer (SSL)
to protect data in transit. This link lists SSL root certificates that
ship on Windows Phone 7:
http://msdn.microsoft.com/en-us/library/gg521150(v=VS.92).aspx
Once sensitive data is on the device, use available
encryption services on the platform to secure the data. Windows Phone 7
supports the following cryptographic algorithms:
AES
HMACSHA1
HMACSHA256
Rfc2898DeriveBytes
SHA1
SHA256
The next covers how to use these algorithms to securely store data on Windows Phone 7.
2. Securely Encrypting Data
The UI takes some
data to encrypt, a password and salt to perform the encryption, and
then a couple of TextBlocks to show the encrypted data as well as
results from decrypting.
The Application Bar is enabled with four buttons:
All the UI data fields and event methods have
corresponding properties on the MainViewModel class. The encryption
operations are actually performed on MainViewModel properties with data
binding bringing the results to the UI. Figure 1 shows the UI layout.
The following using statements are added to the
MainViewModel class to provide the necessary access for stream-based
processing and encryption:
using System.IO;
using System.IO.IsolatedStorage;
using System.Security.Cryptography;
using System.Text;
In addition to the ViewModel data fields backing the UI MainPage.xaml View, four additional methods are added to MainViewModel:
Each method performs the task described by the method
name. These four methods are accessed via the Application Bar buttons
in the View as shown in Listing 1.
Example 1. MainPage.Xaml.cs Code File
using System.Windows;
using System.Windows.Controls;
using EncryptingData.ViewModel;
using Microsoft.Phone.Controls;
namespace EncryptingData
{
public partial class MainPage : PhoneApplicationPage
{
MainViewModel vm;
// Constructor
public MainPage()
{
InitializeComponent();
vm = this.DataContext as MainViewModel;
}
private void EncryptAppBarBtn_Click(object sender, System.EventArgs e)
{
vm.EncryptData();
}
private void DecryptAppBarBtn_Click(object sender, System.EventArgs e)
{
vm.DecryptData();
}
private void SaveIsoAppBarBtn_Click(object sender, System.EventArgs e)
{
vm.SaveEncryptedDataToIsolatedStorage();
}
private void LoadIsoAppBarBtn_Click(object sender, System.EventArgs e)
{
vm.LoadEncryptedDataFromIsolatedStorage();
}
private void PasswordBox_LostFocus(object sender,
System.Windows.RoutedEventArgs e)
{
if (((PasswordBox)sender).Password.Length < 8)
MessageBox.Show("Salt Value must be at least eight characters.",
"Minimum Length Error",MessageBoxButton.OK);
}
}
}
|
The four encryption related methods in MainViewModel code are shown in Listing 2.
Example 2. Methods from MainViewModel.cs Code File
public void EncryptData()
{
using (AesManaged aes = new AesManaged())
{
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(Password,
Encoding.UTF8.GetBytes(SaltValue), 10000);
aes.Key = rfc2898.GetBytes(32);
aes.IV = rfc2898.GetBytes(16);
using (MemoryStream memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream = new CryptoStream(memoryStream,
aes.CreateEncryptor(), CryptoStreamMode.Write))
{
//Encrypt Data with created CryptoStream
byte[] secret = Encoding.UTF8.GetBytes(DataToEncrypt);
cryptoStream.Write(secret, 0, secret.Length);
cryptoStream.FlushFinalBlock();
aes.Clear();
//Set values on UI thread
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
EncryptedData = Convert.ToBase64String(memoryStream.ToArray());
});
}
}
}
}
public void DecryptData()
{
MemoryStream memoryStream = null;
using (AesManaged aes = new AesManaged())
{
//Generate Key and IV values for decryption
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(Password, Encoding.UTF8.GetBytes(SaltValue), 10000);
aes.Key = rfc2898.GetBytes(32);
aes.IV = rfc2898.GetBytes(16);
using (memoryStream = new MemoryStream())
{
using (CryptoStream cryptoStream =
new CryptoStream(memoryStream, aes.CreateDecryptor(),
CryptoStreamMode.Write))
{
//Decrypt Data
byte[] secret = Convert.FromBase64String(EncryptedData);
cryptoStream.Write(secret, 0, secret.Length);
cryptoStream.FlushFinalBlock();
byte[] decryptBytes = memoryStream.ToArray();
aes.Clear();
//Update values on UI thread
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
DecryptedData = Encoding.UTF8.GetString(decryptBytes, 0, decryptBytes.Length);
});
}
}
}
}
public void SaveEncryptedDataToIsolatedStorage()
{
//Save secret to Application Settings
if (EncryptedData != "")
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(StorageKeyName))
{
IsolatedStorageSettings.ApplicationSettings[StorageKeyName] =
EncryptedData;
}
else
{
IsolatedStorageSettings.ApplicationSettings.Add(
StorageKeyName, EncryptedData);
}
}
}
public void LoadEncryptedDataFromIsolatedStorage()
{
//Retrieve secret from Application Settings
if (IsolatedStorageSettings.ApplicationSettings.Contains(StorageKeyName))
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
EncryptedData =
IsolatedStorageSettings.ApplicationSettings[StorageKeyName].ToString();
});
}
else
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
EncryptedData = "";
});
}
}
|
The code generates a Key for AES based on the Password and Salt values provided by the user. The Rfc2898DeriveBytes class is used to generate the HMACSHA1 random number (iteration count of 1,000) for the AES Key and IV values. What's handy with implementing encryption via the ViewModel is that it is easily reusable. The MainViewModel class has zero dependencies on UI.
One other item to note is
that this section demonstrates the only truly secure means to encrypt
data, because it requires a password by the user. This is because the
initial release of the Windows Phone Developer Tools does not include
access to a secure key store. This is a frequently requested feature by
developers so I would bet that it is one of the first features to be
added to the next release of the tools.