Wednesday, November 16, 2011

Encryption in Mango! Part II

In this blog post, we will be creating a simple application in which the following things will happen -

1. The end user can enter a text in a text box which needs to be encrypted.
2. The applicaiton will store the encrypted text in the isolated storage and also show the encrypted bytes in string format to the end user.
3. The end user can choose to view the decrypted text back from the file stored in Isolated storage.
4. The application will read the encrypted bytes from isolated storage, decrypt the contents and show the decrypted text to the end user.

The following is how the application behaves -

The user can choose to enter any text in the first text box under label "Decrypted Text" and then choose the "encrypt" menu item to encypt the contents and store it in Isolated Storage -


On clicing "encrypt" applicaiton bar menu item, the "Hello World!" text will be encrypted and stored in Isolated Storage. The string representation of encrypted bytes stored in Isolated Storage would be shown in Encrypted text text box -

Now the user can choose to see the decrypted text back by selecting the "decrypt" menu bar -


How did we accomplish this programatically?

This example uses multiple things -
1. Usage of application bar
2. Usage of DPAPI and System.Cryptography classes and methods
3. Usage of System.IO and System.IO.IsolatedStorage

If you are not clear on Isolated Storage and Application Bar concepts, i would suggest you to look into my earlier blog posts on these topics.

Code -

Lets first look at the code which encrypts the contents and save contents to the Isolated Storage file -

private void Encrypt_Click(object sender, EventArgs args) {
string encryptedText = String.Empty;
string decryptedText = decryptedTextBox.Text;
byte[] encryptedBytes = null;
if (!String.IsNullOrEmpty(decryptedText)) {
// Convert the string to byte array as ProtectedData.Protect method expects a byte array.
byte[] decryptedBytes = System.Text.Encoding.UTF8.GetBytes(decryptedText);
try {
// Passing the decrypted bytes and setting the optional entropy as null.
encryptedBytes =
ProtectedData.Protect(decryptedBytes, null);
}catch (ArgumentNullException) {
MessageBox.Show("The text to be encrypted can't be empty");
}catch (CryptographicException cryptException) {
MessageBox.Show("Crypt failed , Error Message : " + cryptException.Message);
}
               
catch (NotSupportedException notSupportedException) {                   
MessageBox.Show("OS platform does not support this method. Check with the distributor if you have the right version of Windows Phone , Error Message : " + notSupportedException.Message);
}
catch (OutOfMemoryException) {
MessageBox.Show("OOPS! There is not enough memory on the device to execute this operation.");
}
// Saving the encrypted bytes to Isolated Storage
if (encryptedBytes != null) {
using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()) {
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("Hello.txt", System.IO.FileMode.OpenOrCreate, isolatedStorageFile)) {
BinaryWriter binaryWriter = new BinaryWriter(fileStream);
binaryWriter.Write(encryptedBytes);
binaryWriter.Flush();
binaryWriter.Close();
}
}
encryptedText = System.Text.
Encoding.UTF8.GetString(encryptedBytes, 0, encryptedBytes.Length);
}
}
// Showing the string representation of the encrypted bytes on the screen.
this.decryptedTextBox.Text = String.Empty;
this.encryptedTextBox.Text = encryptedText;
}

In the code above, we are doing the following -

1. First we are retrieving the text from text box and checking if the decrypted text is empty or not.
2. If the decrypted text is not empty or null, then we convert the string to byte array.
3. We use ProtectedData.Protect method whose input is the byte array. We set the optional entropy as NULL. Note - The developers can set entropy to strengthen the key and add one more layer of security.
4. After the bytes have been encrypted, we save them to Isolated Storage using IsolatedStorageFile, IsolatedStorageFileStream and BinaryWriter classes.
Note - If you are writing the string, use Stream Writer. For writing bytes, it is recommended to use BinaryWriter.
5. We are showing the string representation of encrypted bytes on the text box.


Now the code for decryption of the code -

private void Decrypt_Click(object sender, EventArgs args) {

string encryptedText = encryptedTextBox.Text;
string decryptedText = String.Empty;
byte[] encryptedBytes = null;
if (!String.IsNullOrEmpty(encryptedText)) {
//Retrieve the encrypted bytes from the Isolated Storage of phone.
byte[] decryptedBytes = null;
try {
using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()) {
using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("Hello.txt", System.IO.FileMode.Open, isolatedStorageFile)) {

BinaryReader binaryReader = new BinaryReader(fileStream);
encryptedBytes = binaryReader.ReadBytes(Convert.ToInt32(fileStream.Length));

}
}
// Decrypt the encrypted bytes by using Unprotect method of ProtectedData class of System.Security.Cryptography.
decryptedBytes = ProtectedData.Unprotect(encryptedBytes, null);
}
catch (ArgumentNullException) {
MessageBox.Show("The text to be decrypted can't be empty");
}catch (CryptographicException cryptException) {
MessageBox.Show("Crypt failed , Error Message : " + cryptException.Message);
}catch (NotSupportedException notSupportedException) {
MessageBox.Show("OS platform does not support this method. Check with the distributor if you have the right version of Windows Phone , Error Message : " + notSupportedException.Message);
}catch (OutOfMemoryException) {
MessageBox.Show("OOPS! There is not enough memory on the device to execute this operation.");
}               // Convert the decrypted bytes to its string representation
if (decryptedBytes != null) {
decryptedText = System.Text.Encoding.UTF8.GetString(decryptedBytes, 0, decryptedBytes.Length);

}
}

// Showing the decrypted text on the text boxes
this.decryptedTextBox.Text = decryptedText;
this.encryptedTextBox.Text = String.Empty;
}

In the code above, we are doing the following -
1. First we are retrieving the encrypted bytes from Isolated Storage using IsolatedStorageFile, IsolatedStorageFileStream and BinaryReader classes.
2. We use ProtectedData.Unprotect method whose input is the byte array. We set the optional entropy as NULL. Note - The developers can set entropy to strengthen the key and add one more layer of security.
4. After the bytes have been decrypted, we convert them to string representation and show the decrypted sting in the text box.

In my next blog, i will be using this strategy to save complex data types and also will share some tips to use optional entropy field.

No comments:

Post a Comment