This project has moved. For the latest updates, please go here.

This article was taken from my blog at www.stephenhaunts.com

I have recently released a small open source library that I thought might be useful to people. The library is called Block Encrypter it is designed to make asymmetric encryption of  data in .NET / C# easier. The code in this library has been developed over the past year and used in my open source tools SafePad and Text Shredder. The way in which this library goes about encryption has been peer reviewed by many people in the open source community so should give you a level of comfort that it is secure in how it goes about encrypting data. Block Encrypter encrypts data using standard cryptographic primitives like AES, HMAC, PBKDF, and cryptographically secure random number generation.

I have previously discussed AES encryption in .NET in my cryptography series of articles. I also posted an article linking to some really useful videos by Patrick Townsend about how the AES algorithm works. If you are interested in symmetric cryptography I highly recommend watching them.

encryption

First lets look at some usage examples. The main object in the library to call is the Block Encrypter object and this contains methods that allow you to encrypt/decrypt strings or byte arrays of data.

Overview of the Library

The library itself is quite straight forward to use and there are not that many objects to get to grips with. The main entry point for the library is the BlockEncrypter object. This object will then call out to the GzipCompression object, Aes object, and the ByteHelpers object.

Block Encryter Class Diagram

Block Encryter Class Diagram

The library is also well covered in unit tests that exercise the majority of the functionality.

 

Encrypting and Decrypting Strings

 
 
 
 
 
 
const string originalMessage = "This is my message to encrypt.";
 
string encrypted = BlockEncrypter.EncryptStringBlock(originalMessage, Encoding.ASCII.GetBytes("Pa55w0rd"));
string decrypted = BlockEncrypter.DecryptStringBlock(encrypted, Encoding.ASCII.GetBytes("Pa55w0rd"));
 
Assert.AreEqual(originalMessage, decrypted);

In the example above the string “This is my message to encrypt” is encrypted and then decrypted using the password “Pa55w9rd”. Naturally this is a really bad password, but it is just an example.

Encrypting and Decrypting Byte Arrays

 
 
 
 
 
 
 
const string originalMessage = "This is my message to encrypt.";
byte[] testBytes = ByteHelpers.GetBytes(originalMessage);
 
byte[] encrypted = BlockEncrypter.EncryptByteBlock(testBytes, Encoding.ASCII.GetBytes("Pa55w0rd"));
byte[] decrypted = BlockEncrypter.DecryptByteBlock(encrypted, Encoding.ASCII.GetBytes("Pa55w0rd"));
 
Assert.IsTrue(ByteHelpers.ByteArrayCompare(testBytes, decrypted));

Summary Encryption and Decryption Process

Encryption

This process is the same regardless of whether you are encrypting text or data. When encrypting text, the first thing the code does is convert it into a byte array.

  1. Generate a 32byte salt with a cryptographic random number generator. This salt is used to give us extra entropy when encrypting your data.
  2. Compress the data to be encrypted.
  3. Using the password and the salt from step 1, derive an encryption key using a password based key derivation function (RFC2898) and the salt. By using a new salt every time we encrypt we guarantee that even for the same message, the cipher text will be different each time.
  4. Create the AesCryptoServiceProvider object. This is a FIPS Certified version of the AES Algorithm in .NET. Explicitly set the mode to Cipher Block Chaining and the padding to PKCS7. These are the defaults, but for the sake of clarity I made them explicit.
  5. Using the derived key form step 3, then derive a 16 byte initialization vector.
  6. Create a new MemoryStreamCryptoStream and encrypt the data.
  7. Generate a SHA256 based Message Authentication Code (HMAC) of the salt + cipher text using the AES Encryption Key.
  8. Combine the HMAC and the encrypted cipher text into 1 byte array.
  9. Append the original salt from step 1 to the front of the message. The salt is not a secret value. It is there purely to give extra entropy.

Decryption

The decryption process of a block of data is as follows.

  1. Extract the salt form the first 32 bytes of the data block.
  2. Extra the remaining HMAC and encrypted cipher text from the data block.
  3. Using the password and the salt from step 1, derive an encryption key using a password based key derivation function and the salt.
  4. Create the AesCryptoServiceProvider object. This is a FIPS Certified version of the AES Algorithm in .NET. Explicitly set the mode to Cipher Block Chaining and the padding to PKCS7. These are the defaults, but for the sake of clarity I made them explicit.
  5. Derive the initialisation vector from the encryption key.
  6. Calculate a new HMAC of the salt + cipher text using the encryption key. Check that this HMAC matched the original HMAC. If it doesn’t throw an exception and don’t proceed with decryption.
  7. Create a MemoryStream, CyptoStream and decrypt the data.
  8. Decompress the decrypted byte stream. This leaves you with the original message before encryption.

Summary

As you can see there is more just using the AesCryptoServiceProvider class to encrypt and decrypt data securely.

Please don’t use the AesManaged class in .NET as this is not FIPS Certified, so if you need to pass your encrypted data to another system / platform, you will not be able guarantee that the other system can decrypt it.

The generation of the original salt is designed to give you entropy and this means that the original message, if encrypted multiple times, will always produce a different cipher text. This helps guard you against known cipher text attacks.

When it comes to using a password to generate the key, the password based key derivation function (RFC2898) is used to generate the actual encryption key. This derivation function allows you to pass in how many rounds to use when generating the key. In this library I have it defaulted to 70,000, but you can set any number you like. The more rounds you use, the slower it is, but it is safer against brute force attacks. The idea is to slow down the key generator function so brute force cracking of the key becomes prohibitively slow.

If you didn’t want to use a human readable password, you could generate a long cryptographically secure random number instead and pass that into the block encrypter.

We also take message integrity into account by generating a SHA256 based HMAC of the encrypted message and its salt. This differs from just using SHA256 in that the HMAC is also based on the encryption key, so you need to know the key to calculate and check the same HMAC. This allows us to detect if the message has been tampered with in transit or corrupted.

I hope you find this little library useful. Many people have reviewed this code in various different states of development and have offered me much advice on how to improve it and make sure it is secure, so if you need to encrypt data in your systems, this library would be a good base for you to use.

Last edited Apr 3, 2014 at 9:23 AM by stephenhaunts, version 2