Archive for the ‘Security’ Category

Encrypt and decrypt the contents of a file created on a mobile device

Thursday, July 26th, 2007

A screenshot of the example symmetric encryption application I wroteEncrypting the contents of a file is a common task, especially with configuration files which may contain sensitive passwords, or database connectivity information.

Recently I discussed symmetric and asymmetric encryption support within .NET Compact Framework v2.0. These blog entries were heavy in theory and light on actual sample applications.

Microsoft’s 70-540 exam covers knowledge about encryption by outlining a couple of common usage scenarios and expecting candidates are capable of implementing them. One such task is the ability to encrypt and decrypt the contents of a file and this blog entry covers an example implementation of this.

How to use the sample application
The main user interface is a single form. By making selections in the combo boxes at the top of the form you can select the required encryption algorithm and key size.

Whenever you change key sizes, a random encryption key is generated for you and this is inserted into the key text box. If you have a message encrypted with a specific encryption key, you can type it into the key text box manually.

To create an encrypted text file, type your message into the textbox at the bottom of the form and tap the encrypt button. A file save dialog box will appear to ask you where you want to save the encrypted file.

To decrypt a text file, tap the decrypt button and a file open dialog box will appear to ask you to select a file to decrypt. Once you have selected one an attempt will be made to decrypt the message using the encryption key present within the UI, and if successful the cleartext message will be displayed in the textbox.

If you use Pocket Word to open the text files you have encrypted, you should see that they contain no human readable content and simply contain a “garbled mess”. You should only be able to recover your encrypted message by configuring identical encryption parameters within the GUI again and pressing the decrypt button.

How it works
The process of implementing symmetric encryption within the .NET Compact Framework has been covered before, so please refer to that blog entry for technical details on the implementation. The source code of the sample application is also available, and is heavily commented to describe what is happening at each stage of the process.

A high level overview of how this application performs encryption of text files is as follows:

  1. An instance of a class which derives from SymmetricAlgorithm is created.
  2. The LegalKeySizes property is read to determine a list of valid key sizes.
  3. The KeySize and Key properties are configured with the desired values.
  4. The IV property is configured with the desired value (and optionally the BlockSize property is altered).
  5. A FileStream instance is created to allow access to the file.
  6. The FileStream is wrapped in a CryptoStream, which is then used instead of the original file stream (this is what performs the encryption/decryption).

Further work
Questions to ask yourself while reviewing the source code of this sample include:

  • How does a CryptoStream know if it is encrypting or decrypting data?
  • How can I verify if a given key size is valid for the selected encryption algorithm?
  • What exceptions may be thrown during decryption if an incorrect key is utilised?
  • What object oriented concept makes it easy to switch between different symmetric encryption algorithms with only minor code changes?

This sample application only demonstrates the use of symmetric encryption algorithms. As an exercise left to the user, see if you can alter the sample application to use asymmetric encryption by using the RSACryptoServiceProvider class. As part of your solution you should figure out how to export and import the public part of your public/private key pair, so other devices can read your encrypted messages.

The source code for the sample application can be downloaded.

Asymmetric Key Encryption on the Compact Framework

Tuesday, July 24th, 2007

Asymmetric key encryption is useful for use in exchanging data over insecure communication channels. This is due to the use of separate keys for encryption and decryption. This blog entry follows on from the previous one on symmetric key encryption and discusses how to utilise asymmetric key encryption within a .NET Compact Framework application.

Asymmetric Encryption classes within the .NET Compact Framework
The .NET base class library provides Asymmetric Encryption classes within the System.Security.Cryptography namespace. They all derive from the AsymmetricAlgorithm base class.

The .NET Compact Framework base class library provides the following asymmetric encryption classes

  • RSACryptoServiceProvider – This is the .NET implementation of the RSA algorithm named after its three creators – Ronald Rivest, Adi Shamir and Leonard Adleman. It was developed in 1977. This is a wrapper around an unmanaged algorithm implementation provided by the Windows CE Crypto API.
  • DSACryptoServiceProvider – This class is used for digitally signing messages to ensure that they are not tampered with during transit. This is also a managed wrapper around unmanaged code. Since digital signatures and hashing are not part of the current topic I will not discuss this class any further.

Common Asymmetric Algorithm properties
When dealing with the encryption aspect of these crypto service providers there are only a couple of properties of interest defined on the AsymmetricAlgorithm base class:

  • KeySize – the size of the secret key used by the asymmetric algorithm in bits. These are typically much larger than symmetric keys. For example RSA as implemented in the .NET Compact Framework supports keys between 384 and 16384 bits. Setting this property affects the strength of the encryption process.
  • LegalKeySizes – an array of KeySizes objects which outline the range of key sizes supported by the current encryption algorithm.

Likewise there are only a couple of methods defined on the AsymmetricAlgorithm base class.

  • ToXmlString – exports a key pair in the form of an string containing an XML document.
  • FromXmlString – imports a key pair from a string containing an XML document.

You will notice there are no methods for encryption or decryption on the AsymmetricAlgorithm base class. Most of the useful methods (including those used for actual encryption) are actually defined on the classes which derive from AsymmetricAlgorithm.

The most useful methods defined on the RSACryptoServiceProvider class are as follows:

  • Decrypt – a method to decrypt data with the RSA algorithm.
  • Encrypt – a method to encrypt data with the RSA algorithm.
  • ExportParameters – returns a RSAParameters struct, which defines the RSA encryption key pairs (i.e. returns the same data as the ToXmlString method, just in a different format).
  • ImportParameters – imports a public key or key pair from the specified RSAParameters struct.

How to export and import key pairs
Once you have created an instance of the RSACryptoServiceProvider class it will generate it’s own public/private key pair. You can import and export the keys for storage purposes, or to transfer them to another device. In most cases you will probably want to only export the public key (since the private key should be kept a closely guarded secret).

When exporting the keys via the ToXmlString (as XML) and ExportParameters (as a RSAParameters struct) methods, you have the choice of exporting only the public key (false), or both the public key and private keys (true) via a boolean parameter.

The following code sample, demonstrates using these methods:

// Export the public key (pass in true to also export the private keys)
// from device A
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider();
RSAParameters publicKey = rsa1.ExportParameters(false);
string publicKeyXML = rsa1.ToXmlString(false);
 
// ... transmit public key to another device ...
 
// Import the public key
// into device B
RSACryptoServiceProvider rsa2 = new RSACryptoServiceProvider();
rsa2.ImportParameters(publicKey);
rsa2.FromXmlString(publicKeyXML);

Please note that in the code sample I have demonstrated using both the XML and object based methods. In a typically application only one set of methods would be utilised.

Secure private key storage
Your application most likely needs to reuse the same public/private key pair a number of times. This means that once generated you will typically need to store your key pair in a secure manor.

The RSACryptoServiceProvider class includes the ability to save the keys in a secure manor by using the Crypto API CSP key container facility. You should seriously consider using this functionality to store private keys, as it is highly likely that it will be more secure than most solutions you will be able to create manually.

To store your private keys in a CSP key container, perform the following actions within your code:

The .NET Compact Framework then handles creating and retrieving keys automatically. The first time the code executes a unique public/private key pair will be generated and saved into the specific key container. In the future when the RSACryptoServiceProvider instance is created with the same key container name, the keys will automatically be retrieved.

// Create the CspParameters object and set the
// key container name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = "MySampleKeyContainer";
 
// Create a new instance of RSACryptoServiceProvider 
// that accesses the key container "MySampleKeyContainer"
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
 
// Display the key information to the debug window.
Debug.WriteLine("Key added to container: \n  {0}", rsa.ToXmlString(true));

How to encrypt and decrypt data using Asymmetric encryption
The Encrypt() and Decrypt() methods both accept two parameters as follows:

  • rgb – a byte array containing the data to be encrypted or decrypted
  • fOAEP – a boolean flag. If true OAEP data padding is used, otherwise PKCS #1 v1.5 padding is used. This parameter doesn’t really matter as much, as long as encryption and decryption utilise the same value. Controlling this parameter becomes important in scenarios where one end of the encryption process is dictated by a third party system.

The following example demonstrates basic RSA encryption and decryption by providing a couple of small helper functions which will be useful within your own applications.

The methods encrypt (or decrypt) data passed to them in the form of a byte array and return another byte array containing the processed output. These methods utiilise the CSP Key Container storage mechanism to securely store the public/private key pair used to perform the encryption process.

using System.Security.Cryptography;
 
public byte[] Encrypt(byte[] data, string keyContainerName)
{
  // Configure the parameters to indicate the name of the
  // key container which contains our public/private key pair
  CspParameters csp = new CspParameters();
  csp.KeyContainerName = keyContainerName;
 
  // Create an instance of the RSA encryption algorithm
  // and perform the actual encryption
  RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
  return rsa.Encrypt(data, true);
}
 
public byte[] Decrypt(byte[] data, string keyContainerName)
{
  // Configure the parameters to indicate the name of the
  // key container which contains our public/private key pair
  CspParameters csp = new CspParameters();
  csp.KeyContainerName = keyContainerName;
 
  // Create an instance of the RSA encryption algorithm
  // and perform the actual decryption
  RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);
  return rsa.Decrypt(data, true);
}

Please note that if the encryption and decryption code was running on two different devices, you would have to use the technique discussed in the “How to export and import key pairs” section to ensure that the decryptor had access to the public key.

A common request on newsgroup forums is for help in encrypting small amounts of text. Common problems encountered in this scenario include improperly converting the binary data produced by the encryption process back into a text string.

For this reason I have also provided the following helper functions which make it really easy to securely encrypt and decrypt text strings.

using System;
using System.Text;
 
public string EncryptString(string data, string keyContainerName)
{
  // Encrypt a string using the private key stored within the
  // specified key container
  byte dataToEncrypt[] = Encoding.UTF8.GetBytes(data);
  byte encryptedData[] = Encrypt(dataToEncrypt, keyContainerName);
  return Convert.ToBase64String(data);
}
 
public string DecryptString(string data, string keyContainerName)
{
  // Decrypt a string using the public key stored within the
  // specified key container
  byte dataToDecrypt[] = Convert.FromBase64String(data);
  byte decryptedData[] = Decrypt(dataToDecrypt, keyContainerName);
  return Encoding.UTF8.GetString(decryptedData);
}
 
// Example use
 
string myEncryptedString = EncryptString("This is my top secret message",
                                        "SampleKeyContainer");
...
string myDecryptedString = DecryptString(myEncryptedString,
                                         "SampleKeyContainer");

Now that I have provided some rather long discussions on symmetric and asymmetric key encryption within the .NET Compact Framework, I am finally ready to dicuss some practical uses of encryption. In the next few days I aim to cover off some of the encryption related aspects of exam 70-540.

Symmetric Key Encryption on the Compact Framework

Monday, July 23rd, 2007

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();
sa.GenerateKey();
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)
    sb.Append(b.ToString("X"));
  return sb.ToString();
}
 
// Converts the byte array into a Base64 encoded string
public string GetBase64String(byte[] data)
{
  return Convert.ToBase64String(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:

  1. Create a stream to interface to the data you will be reading or writing to
  2. Create and initialise a SymmetricAlgorithm object
  3. Call CreateEncryptor() or CreateDecryptor() to create an ICryptoTransform object
  4. Create a CryptoStream by passing in your stream and ICryptoTransform object
  5. 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.

using System.IO;
using System.Text;
using System.Security.Cryptography;
 
// Configure the desired encryption algorithm parameters
SymmetricAlgorithm sa = new RijndaelManaged();
sa.GenerateKey();
 
// 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.