Encryption 101: Symmetric Algorithms

Earlier this week, we covered one-way encryption using a hash algorithm and a salted hash. If you need to decrypt what you’ve encrypted, these solutions are out the window. The simplest solution for encrypting and decrypting is to use a symmetric algorithm. Data is encrypted using a secret key, and it’s decrypted the same way–using the secret key. (Symmetric!)

It requires a few more steps to accomplish, but overall, it’s still pretty simple. Let’s breakdown the steps:

  1. Select an algorithm
  2. Create a key
  3. Encrypt data
  4. Decrypt data

That doesn’t sound so bad, right!? So let’s do it!

Select an algorithm

The .NET Framework supports a number of different symmetric algorithms, including DES, RC2, Rijndael, and TripleDES. We’ll use TripleDES in this example, so let’s instantiate our crypto provider.

var algorithm = new TripleDESCryptoServiceProvider();

Create a key

Now that we have our crypto provider, creating our secret key is a breeze.

algorithm.GenerateKey();

But wait! That’s not quite it. We also need to generate an initialization vector (IV), which acts as a “randomizer” for the encryption. Don’t worry, though–it’s just as easy as generating the key.

algorithm.GenerateIV();

Encrypt data

We have our key and IV, so we’re ready to encrypt some data! This is a little more complicated, but still not too bad. All we’re doing is creating an ICryptoTransform “encryptor” from our symmetric crypto provider, then using it to write bytes to a CryptoStream. Sounds hard, but it’s really not so bad.

string Encrypt(SymmetricAlgorithm sa, string text)
{
    var encryptor = sa.CreateEncryptor(sa.Key, sa.IV);
    var bytes = Encoding.UTF8.GetBytes(text);
    using (var ms = new MemoryStream())
    {
        using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
        {
            cs.Write(bytes, 0, bytes.Length);
            cs.FlushFinalBlock();
        }
        return Convert.ToBase64String(ms.ToArray());
    }
}

Decrypt data

Now how do we go about decrypting it? Well, not surprisingly–this being a symmetric algorithm and all–it’s nearly identical to encrypting the data. The only difference is that we create a “decryptor” from our crypto provider.

string Decrypt(SymmetricAlgorithm sa, string encrypted)
{
    var decryptor = sa.CreateDecryptor(sa.Key, sa.IV);
    var bytes = Convert.FromBase64String(encrypted);
    using (var ms = new MemoryStream())
    {
        using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
        {
            cs.Write(bytes, 0, bytes.Length);
            cs.FlushFinalBlock();
        }
        return Encoding.UTF8.GetString(ms.ToArray());
    }
}

Putting it all together

Overall, symmetric encryption gives us a quick and easy way to do reasonably secure encryption. To properly decrypt data across applications, you’ll need to share the key and IV that you generated. Make sure to keep these values a secret, though, as they allow anybody to decrypt your sensitive data. Here’s the full example from the pieces above:

namespace adamprescott.net.EncryptionSymmetric
{
    using System;
    using System.IO;
    using System.Security.Cryptography;
    using System.Text;

    class Program
    {
        static void Main(string[] args)
        {
            var p = new Program();
            p.Run();
        }

        void Run()
        {
            Console.Write("Input: ");
            var input = Console.ReadLine();

            using (var algorithm = new TripleDESCryptoServiceProvider())
            {
                algorithm.GenerateKey();
                algorithm.GenerateIV();

                var encrypted = Encrypt(algorithm, input);
                Console.WriteLine("Encrypted: {0}", encrypted);

                var decrypted = Decrypt(algorithm, encrypted);
                Console.WriteLine("Decrypted: {0}", decrypted);
            }

            Console.ReadLine();
        }

        string Encrypt(SymmetricAlgorithm sa, string text)
        {
            var encryptor = sa.CreateEncryptor(sa.Key, sa.IV);
            var bytes = Encoding.UTF8.GetBytes(text);
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                {
                    cs.Write(bytes, 0, bytes.Length);
                    cs.FlushFinalBlock();
                }
                return Convert.ToBase64String(ms.ToArray());
            }
        }

        string Decrypt(SymmetricAlgorithm sa, string encrypted)
        {
            var decryptor = sa.CreateDecryptor(sa.Key, sa.IV);
            var bytes = Convert.FromBase64String(encrypted);
            using (var ms = new MemoryStream())
            {
                using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write))
                {
                    cs.Write(bytes, 0, bytes.Length);
                    cs.FlushFinalBlock();
                }
                return Encoding.UTF8.GetString(ms.ToArray());
            }
        }
    }
}
Advertisement

Author: Adam Prescott

I'm enthusiastic and passionate about creating intuitive, great-looking software. I strive to find the simplest solutions to complex problems, and I embrace agile principles and test-driven development.

Leave a comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: