Encrypting and Signing Data
Many applications store sensitive data that should be encrypted to keep it safe from prying eyes. This may be information about the user or internal data for the application itself. Other information may need to be signed. Signing generates a specialized hash of data that provides a unique signature. If the original data is tampered with, the signature of the data will change. You can verify the signature against the original to determine if the data was modified in any way.
Encryption and signing is handled in the Windows Runtime by the CryptographicEngine class. This class provides services to encrypt, decrypt, sign, and verify the signature of digital content. The EncryptionSigning project contains some simple examples of performing these operations. The main code is located in the MainPage.xaml.cs file.
Encryption and decryption operations require a special key. Think of a key as a password for the encryption and decryption operations. There are two types of keys you can use. The most straightforward is called a symmetric key, which uses the same password or “secret” to both encrypt and decrypt the information.
To produce a key, you use the SymmetricKeyAlgorithmProvider class. You initialize the class by calling OpenAlgorithm with the name of the algorithm you wish to use. You then call CreateSymmetricKey to generate the key for the encryption operation. This same key must be used to decrypt the data later on. You can read the list of valid algorithms in the MSDN documentation at http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.core.symmetrickeyalgorithmprovider.openalgorithm.aspx.
In the example application, the RC4 stream cipher is used to encrypt and decrypt the data. The user is prompted for one of two passwords, and then the passwords are repeated 100 times to fill a buffer. You can use any source data that can be converted to an array of bytes for the key. A helper utility is included in the code to help convert a string to an instance of IBuffer:
var buffer = CryptographicBuffer .ConvertStringToBinary(str.Trim(), BinaryStringEncoding.Utf8); return buffer;
The CryptographicBuffer class provides a set of helper utilities for encryption, decryption, and signing operations. It supports comparing two instances of a buffer, converting between strings and binary arrays using various encodings, decoding and encoding using Base64, and generating a buffer of random data. In this example, it is used to encode the string using UTF8 to a buffer that is returned.
Using the helper method, the code produces the key like this:
var result = await GetPassword(); var provider = SymmetricKeyAlgorithmProvider.OpenAlgorithm("RC4"); var key = provider.CreateSymmetricKey(AsBuffer(result));
When the key is generated, it is a simple step to encrypt the source text with the key. The result is encoded using Base64 so that it can be updated to the TextBlock in the right column for display:
var encrypted = CryptographicEngine.Encrypt(key, AsBuffer(BigTextBox.Text), null); _encrypted = encrypted.ToArray(); BigTextBlock.Text = CryptographicBuffer .EncodeToBase64String(encrypted);
When you encrypt the text, the decrypt button is enabled. The user is given the option to select a password again for the decryption. If the user chooses a password that is different from the one used in the encryption operation, the decrypt process will fail or produce illegible output. The decryption process produces a key the same way the encryption process does and then simply calls the Decrypt method on the CryptographicEngine class:
var decrypted = CryptographicEngine.Decrypt(key, _encrypted.AsBuffer(), null); BigTextBox.Text = AsText(decrypted).Trim();
It is also possible to encrypt and decrypt using an asymmetric key. The AsymmetricKeyAlgorithmProvider is used to generate asymmetric keys. Asymmetric encryption uses two different keys, a “public” key and a “private” key to perform encryption and decryption. This allows you to encrypt the data with your private secret but provide a public key for decryption. It allows third parties to decrypt the data while keeping your secrets safe.
You can learn more about asymmetric keys and see sample code online at http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.cryptography.core.asymmetrickeyalgorithmprovider.openalgorithm.aspx.
The key used to sign data can be generated using the MacAlgorithmProvider class. This class represents a Message Authentication Code (MAC). You can create the key using any one of the popular algorithms including Message-Digest Algorithm (MD5), Secure Hash Algorithm (SHA), and Cipher-based MAC (CMAC). The key is generated much the same way as the encryption key. In the example project, a default password is used to generate the key for the signature:
var provider = MacAlgorithmProvider.OpenAlgorithm("HMAC_SHA256"); var key = provider.CreateKey( AsBuffer(MakeBigPassword(PASSWORD1)));
The signing process generates a buffer the same way the encryption process does. The difference is that you can use the buffer output by encryption to decrypt the message and produce the original. The signature is one-way—you cannot recreate the message from the signature. It’s only function is to compare against an existing message to determine whether or not it has been tampered with.
The signature is generated with a call to the Sign method on the CryptographicEngine class:
_signature = CryptographicEngine.Sign(key, AsBuffer(BigTextBox.Text)).ToArray();
The signature is verified with a call to VerifySignature that will return true if the text has not been altered since the signature was generated:
var result = CryptographicEngine.VerifySignature(key, AsBuffer(BigTextBox.Text), _signature.AsBuffer());
To see how this works, launch the sample application and tap the Sign button. Now tap the Verify button to see that the text has not been altered. Now add a space or other character to the text in the left column and tap Verify again. This time you should receive a message that the text has been tampered with.
Windows 8 provides a set of powerful algorithms for encrypting, decrypting, and signing data. The process is made extremely simple through the use of the CryptographicEngine, CryptographicBuffer, and key provider classes. Use encryption to secure data both internal to your application and for transport over the Internet and use signatures to verify that data has not been tampered with in-transit.