There are two main types of encryption algorithms available within the .NET Compact Framework – symmetric and asymmetric encryption. This blog entry will discuss how to utilise symmetric key encryption, but first we have to outline the difference between Symmetric and Asymmetric encryption (I will discuss asymmetric key encryption in a future blog entry).
Symmetric and Asymmetric Key Encryption
Symmetric encryption algorithms (also known as ciphers) process plain text with a secret encryption key to create encrypted data (called cipher text). The same secret key is used to decrypt the cipher text back to plain text.
Asymmetric encryption (also known as public-key encryption) is a cryptography technique that uses public and private key pairs to encrypt and decrypt data respectably. The private key is a closely guarded secret, while the public key can be freely distributed over untrusted networks. You do not worry who has your public key (you could print it on a 100foot tall banner if you so desired), but you must keep your private key secret.
The two keys are mathematically linked; data encrypted with the public can only be decrypted by the private key and visa versa. So once data is encrypted you can safely assume only the intended recipient can read it.
The disadvantage of symmetric key encryption is that it assumes that the two parties involved have already agreed upon an encryption key in a secure manor. Any insecurity in the key exchange mechanism compromises the security of the data. Conversely the disadvantage of asymmetric encryption algorithms is that they are more computationally expensive and hence slower to work with.
A common technique is to use an asymmetric encryption algorithm to transfer a randomised symmetric encryption key that is then utilised to encrypt the rest of the communication process. SSL work this way for example.
Symmetric Encryption classes within the .NET Compact Framework
The .NET base class library provides Symmetric Encryption classes within the System.Security.Cryptography namespace. They all derive from the SymmetricAlgorithm base class which provides a set of common properties and methods. By deriving from a common base class it is easy for your application to switch among the different encryption algorithms with only minor code changes.
The .NET Compact Framework base class library provides the following symmetric encryption classes:
- RijndaelManaged – Rijndael also known as Advanced Encryption Standard (AES) supports use of 128 to 256 bit keys (in 32bit increments). This is also the only symmetric encryption algorithm within the BCL which has a fully managed implementation.
- DESCryptoServiceProvider – The Data Encryption Standard (DES) supports 56bit keys. This is vulnerable to cracking attacks due to relatively short key length by modern standards.
- TripleDESCryptoServiceProvider – Triple DES is essentially three iterations of the DES encryption process. It utilises 156bit keys, but only 112 bits are effectively utilised for encryption.
- RC2CryptoServiceProvider – This is an encryption standard designed to replace DES. It allows for variable length keys.
You will notice that many of the encryption classes end with the postfix “CryptoServiceProvider”. This is an indication that the encryption algorithm is implemented in native code, as part of the Windows CE Cryptography API. Internally the BCL classes are a thin wrapper over Platform Invoke code which access the actual encryption algorithms.
When deciding which encryption algorithm to use MSDN contains a good article called Performance Comparison: Security Design Choices” which compares the performance of the algorithms.
Common Symmetric Algorithm properties
All symmetric algorithms derive from the System.Security.Cryptography.SymmetricAlgorithm base class and share common properties, the most commonly used properties are described below.
- BlockSize – Symmetric encryption algorithms work on blocks of data. The block size is the number of bits the encryption algorithm processes at a time.
- IV – The initialisation vector (IV) for the encryption process. To prevent patterns forming in blocks of encrypted data, the second block of data is encrypted with the results of the first block and so on. Since the first block has no previous block the initialisation vector is used to obscure the first block of data.
- Key – The secret key used for the symmetric algorithm. If not specified one is automatically generated. After encryption the key must be stored and transfered to the application which performs the decryption.
- KeySize – The size of the secret key in bits. When you create a symmetric algorithm object, the runtime will choose the largest key size supported by the platform. You should only change this if the message recipient does not support the same key size.
- Padding – One of the PaddingMode enumeration values. Determines how the algorithm pads out the last block if the plain text doesn’t fully consume the last block.
Likewise the SymmetricAlgorithim base class provides a number of abstract methods which support the basic encryption processes:
- CreateDecryptor – This returns an instance of an object which implements the ICryptoTransform interface. A Cryptostream object can use this to decrypt a message.
- CreateEncryptor – Similar to the CreateDecryptor method except the ICryptoTransform instance returned performs encryption
- GenerateIV – Generates a random initialisation vector to be used with the symmetric algorithm and assigns it to the IV property.
- GenerateKey – Generates a random key to be used by the symmetric algorithm and assigns it to the Key property.
- ValidKeySize – Determines if the specified key size is valid for the current algorithm.
How to generate symmetric keys
To generate a random key you must use cryptographic strength random numbers. If your “random numbers” are guess-able (or have some form of pattern to them), you cripple the strength of your encryption. You should not use the System.Random class, because the random numbers it generates are not of cryptographic strength.
The easiest way to generate cryptographically strong random keys is to create an instance of your desired symmetric encryption algorithm and call the GenerateKey() method after setting the KeySize property to the desired key length. This will generate a random key of the required length and automatically assign it to the Key property, as the following example demonstrates:
SymmetricAlgorithim sa = new RijndaelManaged();
byte key = sa.Key;
How to display encryption keys
Encryption keys are long sequences of random binary data and as such are difficult to display on a screen or to print out. Two common techniques for displaying keys (or general binary data) in a printable form are hexadecimal and Base64 formatting, as demonstrated by the following code sample:
// Converts the byte array into a hex encoded string
public string GetHexString(byte data)
StringBuilder sb = new StringBuilder();
foreach (byte b in data)
// Converts the byte array into a Base64 encoded string
public string GetBase64String(byte data)
// Example of using the methods defined above
// to display encryption keys
SymmetricAlgorithm sa = new RijndaelManaged();
sa.GenerateKey(); // generates a random key
MessageBox.Show(GetHexString(sa.Key), "Key in Hex Format");
MessageBox.Show(GetBase64String(sa.Key), "Key in Base64 Format");
A hexadecimal string is easier to quote over a phone (since it only uses the characters 0 to 9 and A to F) however it will be longer than a Base64 string which also uses additional printable characters.
You should not use the System.Text.Encoding classes to convert an encryption key to a string. Since the encryption key is binary data, the key is not guaranteed to always consist of valid characters. Passing your encryption key through a text encoding process may corrupt the key, due to the encoding process merging characters and/or removing invalid characters.
How to encrypt and decrypt files by using Symmetric keys
The symmetric encryption algorithms within the BCL implement a streaming model. You create an instance of a CryptoStream and use it to wrap up access to an underlying stream.
The CryptoStream class transforms data (i.e. encrypts or decrypts) as it passes through to the underlying storage stream. The CryptStream class is an example of the decorator design pattern.
To encrypt or decrypt data symmetrically within your application you need to perform the following tasks:
- Create a stream to interface to the data you will be reading or writing to
- Create and initialise a SymmetricAlgorithm object
- Call CreateEncryptor() or CreateDecryptor() to create an ICryptoTransform object
- Create a CryptoStream by passing in your stream and ICryptoTransform object
- Read/Write to the CryptoStream as if it was your original data source
The following example demonstrates the encryption and decryption process by reading and writing the contents of an encrypted text file.
// Configure the desired encryption algorithm parameters
SymmetricAlgorithm sa = new RijndaelManaged();
// Encryption Example
ICryptoTransform transform = sa.CreateEncryptor();
using (Stream outputStream = new FileStream(@"\encrypted.txt", FileMode.Create))
// Wrap the output stream up with a CryptoStream
// which performs the data encryption
using (Stream cryptoStream = new CryptoStream(outputStream, transform, CryptoStreamMode.Write)
// Store data into the cryptoStream (which will encrypt it
// and then pass it along to our outputStream for storage)
using (TextWriter tw = new StreamWriter(cryptoStream))
tw.WriteLine("Hello this my message to encrypt!");
// Decryption example
transform = sa.CreateDecryptor();
using (Stream inputStream = new FileStream(@"\encrypted.txt", FileMode.Open))
// Wrap the input stream up with a CryptoStream
// which performs the data decryption
using (Stream cryptoStream = new CryptoStream(inputStream, transform, CryptoStreamMode.Read))
// Read data into the cryptoStream (which will fetch encrypted
// data from the inputStream and then decrypt it before returning
// it to us)
using (TextReader tr = new StreamReader(cryptoStream))
MessageBox.Show(tr.ReadToEnd(), "Unencrypted Data");
If you look at the contents of the encrypted.txt file on the PDA device you will notice that it looks like random data. You can not determine what the message is by looking at it.
The encrypted contents of the file is binary data. If you must place this contents into a textbox control within a GUI, or send it in an email etc, you will most likely have to encode it using one of the techniques discussed in the section above about displaying encryption keys.
Notice: Typically the encryption and decryption processes would be in different parts of the application, or even on different devices. In this case you would also need to come up with a mechanism which ensures both parts of the code utilise the same initialisation vector (IV) and key parameters. Otherwise you can not be able to successfully decrypt the message.