Av rating:
Total votes: 9
Total comments: 2


Matteo Slaviero
Symmetric Encryption
04 January 2010

Cryptography is an increasing requirement for applications, so it is great that it is part of the .NET framework. Matteo builds on his first article that explained Asymmetric Cryptography and Digital Signatures, and tackles Symmetric Encryption and how to implement it in the .NET Framework.

Symmetric encryption is the oldest cryptographic technique used to transmit or store digital data  securely.

Data that has been encrypted with symmetric encryption is considered to be confidential, in the sense that only those entities (persons or systems) who have the key can understand what the data means.

Cryptography is a security-related technology, but it works differently to others. Rather than preventing unauthorized entities from accessing the information, cryptography prevents them from understanding what the data means. Notice that encrypted data is still data, but without meaning in relation to its purpose. So, the encryption process transforms data into other data that has no meaning.

With symmetric encryption, confidentiality is guaranteed by the use of a secret key. With this key, and a mathematical algorithm, data is converted to an unintelligible form. By using the same key, and applying the mathematical algorithm in the reverse way, the original data can be reconstituted. The algorithm is said to be a two-way algorithm.

Symmetric algorithms can be divided into two main classes: stream algorithms and block algorithms. Stream Algorithms operate directly on a stream of bytes whereas block algorithms  operate by transforming fixed-length groups of bits, a block,  at a time Block algorithms are most commonly used in the IT world today.

This article explains which symmetric algorithms are implemented in the .NET framework base classes, and how to apply them to encrypt and decrypt data.

Symmetric Encryption overview

Before I describe how to use symmetric encryption in the .NET framework, I should say a bit about how block symmetric algorithms work.

We have already mentioned that block symmetric algorithms work on blocks of data at a time. The data to be encrypted is divided into blocks of bits of fixed length and a transformation involving the secret key is applied on each block. The type of transformation depends on the selected algorithm.

At this stage, it is important to notice that identical blocks of data are transformed in the same manner inside the blocks sequence. This can be a security issue. Think about an image file. This is composed of blocks of data that, depending on the image format, might set the color of a pixel on the screen. Suppose you want to encrypt this image.  Suppose, also, that you happen to set, as block unit for the image,  the same length of block that specifies a pixel color. By encrypting it, the “pixel-block” will be encrypted into a different block of data. Remember what we say in the introduction. Encrypted data is again data, but with a different meaning. The encryption transforms a block of bytes into a different block of bytes and so a color would, in those circumstances, become a different color.  If the identical blocks are encrypted in the same manner, we obtain an image with colors changed. The result is that the image is still intelligible to the user that sees it.

To solve this issue, algorithms designers introduced different way to use the same symmetric algorithms on the data blocks. Those are referred as Chiper Modes. The most common approach is to take the previous encrypted data block and combine it with the current data block. This introduces some sort of randomness on the output encrypted blocks sequence. The first block is combined with a dummy initial block, named the initialization vector (IV). Sometimes data is not available block by block (as data that comes from a network stream) and the encryption system should retain data in memory until all blocks arrive. This could be dangerous from a security point of view. The issue can be solved by what is referred to as feedback. Small amount of data than those that forms a block are combined with an equal portion of the previous encrypted block until all the block arrives. The final combined block is  then encrypted.

Another issue comes from the block nature of the symmetric algorithm. If the initial data isn’t an exact multiple of the block size utilized, the final block cannot be encrypted. Again, algorithms designers get around this problem by padding the final block with extra data to the required  length. ‘Padding’ refers to the method used to expand the final data block.

The way in which Padding works is not the only influence on the security of the cryptographic algorithm. Another factor is the length of the key used.  The longer the key, the more secure the encrypted data. The trade-off is that  more computational resources are required. For today’s needs, keys of 128-bit or 256-bit length are adopted.

Symmetric Encryption and .NET Framework

The .NET Framework rationalizes the block symmetric algorithms implemented on it by defining the base abstract class SymmetricAlgorithm that you can find under the System.Security.Cryptography namespace. Each symmetric algorithm is derived from it.

The main principal properties defined on SymmetricAlgorithm class are given by:

All the classes that perform symmetric encryption inherit or derive the previous properties. Those classes, contained on the same namespace of the SymmetricAlgorithm class, are given by:

SymmetricAlgorithm

Aes

            AesCryptoServiceProvider

             AesManaged

Rjindael

                             RjindaelManaged

 TripleDES

             TripleDESCryptoServiceProvider

 DES

             DESCryptoServiceProvider

 RC2

             RC2CryptoServiceProvider

As you can see, algorithms implemented by .NET Framework are: AES, Rjindael, TripleDES, DES and RC2.

Classes on the first level on the derivation tree (the classes Aes ,Rjindael, TripleDES, DES and RC2) define properties related to the specific algorithm. They also implement  the static Create() method that allows us  to create an instance of the object.

The second level on the derivation tree contains all the methods needed by the SymmetricAlgorithm derived object to operate. The two principal methods are given by:

They received, as input, the secret key and the initial IV; and they return a special object that implements the ICryptoTransform interface. We will call this object the Encryptor if we want to encrypt data, otherwise we call it the Decryptor.

This object has methods that permit it to transform arrays of bytes in their encrypted counterpart and vice versa. It is used in conjunction with the CryptoStream object. You can find it under the System.Security.Cryptography namespace.

We will see shortly how to use this object to encrypt/decrypt data with the .NET framework.

Notice that some classes on the second derivation tree end with the suffix CryptoServiceProvider, others with the suffix Managed. The first class of objects utilizes native code to perform cryptographic operation (that relies on the Cryptographic Services Providers defined on the Microsoft® CryptoApi), the second try to utilize only Managed code.

Encrypt and Decrypt Data with .NET Framework

We are now able to use the .NET  Framework base classes to perform encryption and decryption of data.

We will encrypt and decrypt the string “Hello World … !” using, as symmetric algorithm, the Advance Encryption Standard (AES) algorithm.

To do so, we must:

  1. Create an AesCryptoServiceProvider (or an AesManaged) object.
  2. Initialize it with a secret key and an IV (as bytes arrays)
  3. Create the Encryptor or Decryptor object.
  4. Use it in conjunction with a CryptoStream objects that will encrypt and decrypt our data.

We start by creating the secret key and the IV. We need to know their length first. To select the right key and IV lengths, we can browse the LegalKeysSize and LegalBlockSize properties of the SymmetricAlgorithm class. Doing so, we found that 128 bit (and so 16 bytes) is a possible choice for both.  We will take this value.

Notice that, from what we say previously, the IV length must be the same of the block size, being the IV mixed byte by byte with the first block to encrypt.

Now, to create the key, we could select a key phrase, convert it in a byte array with the System.Text.Encoding class and get what we need. This is not the right way to do so. Cryptographic keys must be “well done” in the sense that they must have some “special form” to be secure. Without entering into detail, a good way to create our password is to use the class System.Security.Cryptography.Rfc2898DeriveBytes. This class uses the RFC2898 to generate a “well done” cryptographic key, starting from an initial string. Leaving to the RFC2898 the details about what a ‘salt’ is, ‘salt’, we must generate it first (as a byte array). The length of the ‘salt’ must be at least 8 bytes (that, with ASCII or UTF8 encoding is equal to 8 characters). So:

//create the initial salt

byte[] salt = Encoding.Default.GetBytes("abcdefgh");

//create the key generator

Rfc2898DeriveBytes keyGenerator = new Rfc2898DeriveBytes("demo", salt);

We can now create the key and the IV:

//create the secret key 128-bit long

byte[] key = keyGenerator.GetBytes(16);

 

//create the iv 128-bit long

byte[] iv = keyGenerator.GetBytes(16);

The GetBytes method of the Rfc2898DeriveBytes is reproducible. Given a fixed salt and password, each time we call the GetBytes(n), with n fixed, we will obtain the same value. This is very important because the key and IV must be recreated each time we want to decrypt data. If the GetBytes method produces different values on every call, we will not be able to decrypt data. Remember to save the ‘salt’ and the initial password in some safe place.

The next step is to encrypt our message. To do so we must create the Encryptor first. We want the Encryptor to encrypt data on the basis of the AES algorithm:

//create the crypto service provider

AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider();

 

//create the ICryptoTransform object

ICryptoTransform w = aesProvider.CreateEncryptor(key, iv);

We must now create the CryptoStream object.  Its constructor accepts, as input parameters, a stream, an ICryptoTransform object and a CryptoStreamMode enum value. The stream to pass will be a stream where data will be written in an encrypted form, the ICrpytoTransform object will be the Encryptor created and the CryptoStreamMode enum value will be Write, stating that we want to write encrypted data on the input stream. For this, we can use the MemoryStream class, defined under the System.IO namespace.

//create the memory stream object

MemoryStream mStream = new MemoryStream();

 

//create the crypto stream object

CryptoStream wStream =

                new CryptoStream(mStream, w, CryptoStreamMode.Write);

Now we are able to encrypt our data. We must transform it into a byte array first:

//convert the string into a bytes array

byte[] buffer = Encoding.Default.GetBytes("Hello World ...!");

 

To encrypt the message we will use the Write method of the CryptoStream object, as we do with all other streams. The encrypted data will be written on the MemoryStream object.

//write on the stream encrypting the messagegege

wStream.Write(buffer, 0, buffer.Length);


wStream.FlushFinalBlock();

Notice that, as with all other streams defined on the .NET Framework, the Flush method must be performed to complete the writing of data on the underlying stream: The CryptoStream class implements a special FlushFinalBlock() method to do the same thing. The name reminds us the block-nature of the encryption process.

With the FlushFinalBlock method-call, the encryption of our data ends.  At this stage, the encrypted data is stored in the MemoryStream object.  We can read it as we would with all other streams.

To decrypt our data we must perform the same steps as for encryption. In this case, the Decryptor must be created and the CryptoStreamMode must be set to Read. Data to decrypt must be taken from the previous generated stream containing the encrypted data.

//create the Decryptor

ICryptoTransform r = aesProvider.CreateDecryptor(key, iv);

 

//create the crypto stream object

CryptoStream rStream = new

        CryptoStream(mStream, r, CryptoStreamMode.Read);

Now, our data can be recovered in its original form by simply reading it from the CryptoStream object. We can use the StreamReader  class for this. You can find it under the System.IO namespace:

//create the stream reader

StreamReader reader = new StreamReader(rStream);

 

//get the message form the stream

String message = reader.ReadLine();

If you try to check the content of the message variable, you will see that our encrypted message was successfully decrypted and stored on it.

Conclusion

We end this article by providing some links so you can go deeper into the concepts we’ve touched on:

http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation: It describes the most used Chiper Modes for symmetric encryption. In it, you will find an interesting example about images encryption in relation to the Chiper Mode used.

http://en.wikipedia.org/wiki/Padding_(cryptography): It contains information about the Padding Modes more often utilized.

http://www.ietf.org/rfc/rfc2898.txt: Link to the RFC 2898 that describe the way in which “well done” keys can be derived from an initial password.

http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf: Official AES (Advance Encryption Standard) specifications. In it you can discover how some concepts explained in this papers are keep in consideration when a new standard is made.



This article has been viewed 2964 times.
Matteo Slaviero

Author profile: Matteo Slaviero

Matteo Slaviero is a .NET (C#) consultant who specializes in cryptographic science. He recently started Cassandra Research Center (www.we-cassandra.com) to develop products for cryptography, X509 certificates and PKI (see the we-coffee site at www.we-coffee.com)

Search for other articles by Matteo Slaviero

Rate this article:   Avg rating: from a total of 9 votes.


Poor

OK

Good

Great

Must read
 
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: Use of IV is flawed
Posted by: DuncanSmart (view profile)
Posted on: Wednesday, January 06, 2010 at 4:29 AM
Message: Matteo, your use of the IV is flawed in that sending the same plaintext with the same key will result in identical cipertext. An interloper could deduce useful information from this alone. The IV should be random but just sent in the clear along with the cipertext: see http://en.wikipedia.org/wiki/Initialization_vector

This is a particular bugbear of mine because nearly *every* article on .NET crypto makes this same mistake, and I think someone "who specializes in cryptographic science" should be using the IV correctly.

Subject: RE: Use of IV is flawed
Posted by: conseguenza (view profile)
Posted on: Thursday, January 07, 2010 at 2:25 AM
Message:

The article aims to introduce symmetric cryptography briefly and simply, focusing on the principal concept of cryptography. It does not seek to analyze all the complexity behind cryptography, as this would confuse the beginner. The article intentionally avoids any discussion of "sending content". For this, other algorithms such as  SSL or standards as PKCS7 were developed. In order to effectively exchange data, a lot of extra work other than the IV generation is required, such as choosing the protocol to use, the standard to use for encoding the message and so on ... 


It makes no sense to try to analyze the solution adopted without knowing the goals of the solution. Consider the code I provide. Let’s suppose it will be used on a web application in which a user logs on to the system, inserts some text and encrypts it with a password provided at that time (so, not the static "demo"). What is the probability that different users insert the same text with the same password? Is it high enough to justify avoiding the  IV risk by  implementing a more complicated solution to develop and maintain?  What sort of improvement would you expect to obtain by using this more complicated solution, in the light of such a  very  low probability of text and password match ? .. this what I mean when I say that solutions must be assessed on the overall context, not just on the basis of what the "manual of the moment" says.


 






recommended site pinvoke

PInvoke.net is a user-driven wiki which provides .NET developers with native method signatures, so they don't have to spend time writing them from scratch.




Has .NET Reflector Saved Your Bacon?
 We think Reflector is a fantastic tool, and we know you do too. We'd love to hear about the times... Read more...

The Managed Heap
 Because Red-Gate's .NET team works closely with the users of their products in order to try to fit the... Read more...

How to build a Query Template Explorer
 Having introduced his cross-platform Query Template solution, Michael now gives us the technical... Read more...

Using Three Flavors of LINQ To Populate a TreeView
 LINQ is a valuable technology. LINQ to XML, LINQ to Objects and LINQ to XSD, in particular, can save... Read more...

'Methodist': Make .NET Reflector come alive with IronPython
 It is great to be able to inspect the contents of an assembly with .NET Reflector, but to really... Read more...

A Complete URL Rewriting Solution for ASP.NET 2.0
 Ever wondered whether it's possible to create neater URLS, free of bulky Query String parameters?... Read more...

Visual Studio Setup - projects and custom actions
 This article describes the kinds of custom actions that can be used in your Visual Studio setup project. Read more...

.NET Application Architecture: the Data Access Layer
 Find out how to design a robust data access layer for your .NET applications. Read more...

Web Parts in ASP.NET 2.0
 Most Web Parts implementations allow users to create a single portal page where they can personalize... Read more...

Configuring Forms Authentication in SharePoint 2007
 Damon Armstrong provides a step-by-step guide to the processes, quirks and pitfalls of setting up... Read more...

Over 150,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.

Join Simple Talk