tags:

views:

314

answers:

5

I am after a symmetric encryption/decryption routine in C#. I know there have been a few questions on this topic before, but most of the answers seem to be about the philosophy of encryption rather than giving actual code.

What I really want is someone to fill in the following functions -

public string Encrypt(string message, string key)
{

}

public string Decrypt(string message, string key)
{

}

Update: I'd really like to see some code, rather than just links. Many thanks!

A: 

GPG for data at rest. TLS for data in motion.

GPG http://sourceforge.net/projects/starksoftopenpg/

jms
don't forget bagels for breakfast.
GregS
+2  A: 

what u want are cryptoserviceproviders in the class library

like this one for AES

http://msdn.microsoft.com/en-us/library/system.security.cryptography.aescryptoserviceprovider_members.aspx

pm100
+1  A: 

Convert your text, key and initialization vector to bytes first using the encoding of your choice. Then use the triple DES provider, as demonstrated here:

http://msdn.microsoft.com/en-us/library/system.security.cryptography.tripledes.aspx

Or the one for AES, if you think triple DES is too old-school, or whatever.

Out of curiosity, how are you planning on communicating the secret key?

Eric Lippert
The purpose is to encrypt a piece of data that will sit on the users machine, and which the system will read back in when it starts again. So I was planning to just hard code the key in the system code.
CraigS
So you're trying to encrypt data to stop the user reading it?
Anon.
Yes. For more context, see this problem and solution - http://stackoverflow.com/questions/2130043/secure-software-license-usage-audit-log/2130461#2130461
CraigS
For DES, the key and IV can be anything string of characters, right?
CraigS
Hardcoding the key in the source of a .NET application is hopelessly insecure. All the user has to do is download Reflector and the key is right there in plain sight.
Will Vousden
+3  A: 

Well for starters keys are not strings, keys are binary blobs. PlainText is the same, it's not actually text, again it's a binary blob.

Now of course you can convert strings to byte arrays using Encoding.UTF8.GetBytes(message), however when converting keys back and forth it's a little more complicated, you usually use Convert.ToBase64String and Convert.FromBase64String.

Don't forget that block ciphers also need one more thing, the Initialization Vector, so really your method signatures should be

byte[] Encrypt(byte[] plainText, byte[] key, byte[] iv)

byte[] Decrypt(byte[] cipherText, byte[] key, byte[] iv)

The key and IVs must be cryptographically secure random numbers, don't just type them and don't use C#'s Random function. The size of the key and the IV depend on the cipher algorithm used, and can be accessed by the properties on the classes.

To generate a CSRPNG you do something like

RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] key = new byte[algorithm.KeySizeValue / 8];
rng.GetBytes(key);
byte[] iv = new byte[algorithm.BlockSizeValue / 8];
rng.GetBytes(iv);

You can also use the Rfc2898DeriveBytes class to derive a key and IV from a password and a salt, but again the salt should be a cryptographically secure random number. You should also note when you create a symmetric algorithm a secure key and IV is generated for you.

This way you can then choose the correct encoding for your text, be it UTF8, ASCII or whatever. The links have enough samples so cutting and pasting in here is rather pointless.

blowdart
The IVs do not need to be cryptographically secure, only the keys do.
orip
Not true, in CBC mode, the IV must be unpredictable at the time of encryption
blowdart
Thanks, wasn't aware of that.
orip
+3  A: 

Look at the example code at the bottom of this page.

Copy-pasting it here:

int Rfc2898KeygenIterations= 100;
int AesKeySizeInBits = 128;
String Password = "VerySecret!";
byte[] Salt = new byte[16];
System.Random rnd = new System.Random(); 
rnd.NextBytes(Salt);
byte[] rawPlaintext = System.Text.Encoding.Unicode.GetBytes("This is all clear now!");
byte[] cipherText= null;
byte[] plainText= null;
using (Aes aes = new AesManaged())
{
    aes.Padding = PaddingMode.PKCS7;
    aes.KeySize = AesKeySizeInBits;
    int KeyStrengthInBytes= aes.KeySize/8;
    System.Security.Cryptography.Rfc2898DeriveBytes rfc2898 =
        new System.Security.Cryptography.Rfc2898DeriveBytes(Password, Salt, Rfc2898KeygenIterations);
    aes.Key = rfc2898.GetBytes(KeyStrengthInBytes);
    aes.IV = rfc2898.GetBytes(KeyStrengthInBytes);
    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
        {
            cs.Write(rawPlaintext, 0, rawPlaintext.Length);
        }
        cipherText= ms.ToArray();
    }

    using (MemoryStream ms = new MemoryStream())
    {
        using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
        {
            cs.Write(cipherText, 0, cipherText.Length);
        }
        plainText = ms.ToArray();
    }
}
string s = System.Text.Encoding.Unicode.GetString(plainText);
Console.WriteLine(s);
orip
Ewww, using the non-secure Random to create the salt? Bad bad idea.
blowdart
@blowdart - Nope. Salt and IV need to be as unique as possible, but generating them securely means nothing. Secure random means random that's hard to predict, and you don't care if your IV or salt are predicted - they're passed/stored in plaintext anyway.
orip
@blowdart - I concede your point about IV in CBC mode. It doesn't hold for for salt in PBKDF2 though.
orip