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:
- Select an algorithm
- Create a key
- Encrypt data
- 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()); } } } }