tags:

views:

13170

answers:

11

I'm looking for very simple encrypt and decrypt functionality for some data. It's not mission critical. I need something to keep honest people honest, but something a little stronger than ROT13 or Base64.

I'd prefer something that is already included in the .Net framework 2.0 so I don't have to worry about any external dependencies.

Pre-emptive EDIT: I really don't want to have to mess around with public/private keys, etc. I don't know much about encryption, but I do enough to know that anything I wrote would be less than worthless...in fact, I'd probably screw up the math and make it trivial to crack.

+1  A: 

Try DES or Triple DES

Mike Thompson
+1  A: 

The namespace System.Security.Cryptography contains the TripleDESCryptoServiceProvider and RijndaelManaged classes

Don't forget to add a reference to the System.Security assembly.

Mitch Wheat
+1  A: 

You could also use DPAPI.

JasonS
+21  A: 

Yes, add the System.Security assembly, import the System.Security.Cryptography namespace. Here's a simple example of a symmetric (DES) algorithm encryption:

DESCryptoServiceProvider des = new DESCryptoServiceProvider();
des.GenerateKey();
byte[] key = des.Key; // save this!

ICryptoTransform encryptor = des.CreateEncryptor();
// encrypt
byte[] enc = encryptor.TransformFinalBlock(new byte[] { 1, 2, 3, 4 }, 0, 4);

ICryptoTransform decryptor = des.CreateDecryptor();

// decrypt
byte[] originalAgain = decryptor.TransformFinalBlock(enc, 0, enc.Length);
Debug.Assert(originalAgain[0] == 1);
ZeroBugBounce
This is a nice, compact two-way encryption. The only caveat is that DES is no longer considered state-of-the-art security. That title now goes to the AES algorithm I discuss below.
Mark Brittingham
@richdiet. I'm sorry I unaccepted your answer. The other answer with 37+ votes because it is more current. Thank you for your answer, as it is still a good one.
Matt Dawdy
+1  A: 

If you just want simple encryption (i.e., possible for a determined cracker to break, but locking out most casual users), just pick two passphrases of equal length, say:

deoxyribonucleicacid
while (x>0) { x-- };

and xor your data with both of them (looping the passphrases if necessary). For example:

1111-2222-3333-4444-5555-6666-7777
deoxyribonucleicaciddeoxyribonucle
while (x>0) { x-- };while (x>0) {

Someone searching your binary may well think the DNA string is a key, but they're unlikely to think the C code is anything other than uninitialized memory saved with your binary.

paxdiablo
Interesting idea. I'm not sure I'd "believe" source code in a binary - but how about adapting the idea to use an error message as the passphrase?
Jon Skeet
I prefer using an md5 hash of some cleartext string that already exists in the application (error message or so).
Treb
A: 

I know you said you don't care about how secure it is but if you chose DES you might as well take AES it is the more up to date encryption method

Harald Scheirich
+2  A: 

Encryption is easy: as others have pointed out, there are classes in the System.Security.Cryptography namespace that do all the work for you. Use them rather than any home-grown solution.

But decryption is easy too. The issue you have is not the encryption algorithm, but protecting access to the key used for decryption.

I would use one of the following solutions:

  • DPAPI using the ProtectedData class with CurrentUser scope. This is easy as you don't need to worry about a key. Data can only be decrypted by the same user, so no good for sharing data between users or machines.

  • DPAPI using the ProtectedData class with LocalMachine scope. Good for e.g. protecting configuration data on a single secure server. But anyone who can log into the machine can encrypt it, so no good unless the server is secure.

  • Any symmetric algorithm. I typically use the static SymmetricAlgorithm.Create() method if I don't care what algorithm is used (in fact it's Rijndael by default). In this case you need to protect your key somehow. E.g. you can obfuscate it in some way and hide it in your code. But be aware that anyone who is smart enough to decompile your code will likely be able to find the key.

Joe
+70  A: 

Other answers here work fine, but AES is a more secure and up-to-date encryption algorithm. This is a class that I obtained a few years ago to perform AES encryption that I have modified over time to be more friendly for web applications (e,g. I've built Encrypt/Decrypt methods that work with URL-friendly string). It also has the methods that work with byte arrays.

NOTE: you should use different values in the Key and Vector arrays! You wouldn't want someone to figure out your keys by just assuming that you used this code as-is! All you have to do is change some of the numbers (must be <= 255) in the Key and Vector arrays (I left one invalid value in the Vector array to make sure you do this...).

Using it is easy: just instantiate the class and then call (usually) EncryptToString(string StringToEncrypt) and DecryptString(string StringToDecrypt) as methods. It couldn't be any easier (or more secure) once you have this class in place.


using System;
using System.Data;
using System.Security.Cryptography;
using System.IO;


public class SimpleAES
{
    // Change these keys
    private byte[] Key = { 123, 217, 19, 11, 24, 26, 85, 45, 114, 184, 27, 162, 37, 112, 222, 209, 241, 24, 175, 144, 173, 53, 196, 29, 24, 26, 17, 218, 131, 236, 53, 209 };
    private byte[] Vector = { 146, 64, 191, 111, 23, 3, 113, 119, 231, 121, 2521, 112, 79, 32, 114, 156 };


    private ICryptoTransform EncryptorTransform, DecryptorTransform;
    private System.Text.UTF8Encoding UTFEncoder;

    public SimpleAES()
    {
        //This is our encryption method
        RijndaelManaged rm = new RijndaelManaged();

        //Create an encryptor and a decryptor using our encryption method, key, and vector.
        EncryptorTransform = rm.CreateEncryptor(this.Key, this.Vector);
        DecryptorTransform = rm.CreateDecryptor(this.Key, this.Vector);

        //Used to translate bytes to text and vice versa
        UTFEncoder = new System.Text.UTF8Encoding();
    }

    /// -------------- Two Utility Methods (not used but may be useful) -----------
    /// Generates an encryption key.
    static public byte[] GenerateEncryptionKey()
    {
        //Generate a Key.
        RijndaelManaged rm = new RijndaelManaged();
        rm.GenerateKey();
        return rm.Key;
    }

    /// Generates a unique encryption vector
    static public byte[] GenerateEncryptionVector()
    {
        //Generate a Vector
        RijndaelManaged rm = new RijndaelManaged();
        rm.GenerateIV();
        return rm.IV;
    }


    /// ----------- The commonly used methods ------------------------------    
    /// Encrypt some text and return a string suitable for passing in a URL.
    public string EncryptToString(string TextValue)
    {
        return ByteArrToString(Encrypt(TextValue));
    }

    /// Encrypt some text and return an encrypted byte array.
    public byte[] Encrypt(string TextValue)
    {
        //Translates our text value into a byte array.
        Byte[] bytes = UTFEncoder.GetBytes(TextValue);

        //Used to stream the data in and out of the CryptoStream.
        MemoryStream memoryStream = new MemoryStream();

        /*
         * We will have to write the unencrypted bytes to the stream,
         * then read the encrypted result back from the stream.
         */
        #region Write the decrypted value to the encryption stream
        CryptoStream cs = new CryptoStream(memoryStream, EncryptorTransform, CryptoStreamMode.Write);
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
        #endregion

        #region Read encrypted value back out of the stream
        memoryStream.Position = 0;
        byte[] encrypted = new byte[memoryStream.Length];
        memoryStream.Read(encrypted, 0, encrypted.Length);
        #endregion

        //Clean up.
        cs.Close();
        memoryStream.Close();

        return encrypted;
    }

    /// The other side: Decryption methods
    public string DecryptString(string EncryptedString)
    {
        return Decrypt(StrToByteArray(EncryptedString));
    }

    /// Decryption when working with byte arrays.    
    public string Decrypt(byte[] EncryptedValue)
    {
        #region Write the encrypted value to the decryption stream
        MemoryStream encryptedStream = new MemoryStream();
        CryptoStream decryptStream = new CryptoStream(encryptedStream, DecryptorTransform, CryptoStreamMode.Write);
        decryptStream.Write(EncryptedValue, 0, EncryptedValue.Length);
        decryptStream.FlushFinalBlock();
        #endregion

        #region Read the decrypted value from the stream.
        encryptedStream.Position = 0;
        Byte[] decryptedBytes = new Byte[encryptedStream.Length];
        encryptedStream.Read(decryptedBytes, 0, decryptedBytes.Length);
        encryptedStream.Close();
        #endregion
        return UTFEncoder.GetString(decryptedBytes);
    }

    /// Convert a string to a byte array.  NOTE: Normally we'd create a Byte Array from a string using an ASCII encoding (like so).
    //      System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
    //      return encoding.GetBytes(str);
    // However, this results in character values that cannot be passed in a URL.  So, instead, I just
    // lay out all of the byte values in a long string of numbers (three per - must pad numbers less than 100).
    public byte[] StrToByteArray(string str)
    {
        if (str.Length == 0)
            throw new Exception("Invalid string value in StrToByteArray");

        byte val;
        byte[] byteArr = new byte[str.Length / 3];
        int i = 0;
        int j = 0;
        do
        {
            val = byte.Parse(str.Substring(i, 3));
            byteArr[j++] = val;
            i += 3;
        }
        while (i < str.Length);
        return byteArr;
    }

    // Same comment as above.  Normally the conversion would use an ASCII encoding in the other direction:
    //      System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    //      return enc.GetString(byteArr);    
    public string ByteArrToString(byte[] byteArr)
    {
        byte val;
        string tempStr = "";
        for (int i = 0; i <= byteArr.GetUpperBound(0); i++)
        {
            val = byteArr[i];
            if (val < (byte)10)
                tempStr += "00" + val.ToString();
            else if (val < (byte)100)
                tempStr += "0" + val.ToString();
            else
                tempStr += val.ToString();
        }
        return tempStr;
    }
}
Mark Brittingham
+1 This should of been the accepted answer. Awesome answer..Thanks!!!
Donny V.
@Mark: kudos for the great implementation!
p.campbell
Thanks - this is one of my favorite answers and I'm happy that folks are getting use out of it. Some folks think that you should salt the beginning of the encrypted string to avoid discovery of the Vector array but it really depends on just how paranoid you are about someone trying to decrypt your strings and whether they know what is being encrypted to begin with.
Mark Brittingham
Great answer! Thanks!
sshow
The `using` police (that's not me) might be after you for some of the stream usage
Chris S
Would that be to ensure that the memoryStream is closed? I use "using" much more now than I did when I wrote this algorithm so I can see your point. Don't want to change this without testing it, however, so it might be a little while...
Mark Brittingham
@Chris, there's no benefit to Disposing of MemoryStreams -- they're not like normal streams that hold an OS resource -- they just hold a buffer object that will be collected as all other in-memory objects will be.
Frank Krueger
The Vector array has a number that is too large, 2521. Nice class!
AndyMcKenna
@AndyMcKenna - That's done on purpose so that you change the values in the arrays, as Mark notes in the second paragraph.
Pauk
Pauk's right. You REALLY shouldn't use the keys shown in the code. Change 'em to your own. With a "bad" key, you'll have no choice ;-)
Mark Brittingham
Hi Mark, For a given string, is there a way to shorten the length of the encrypted string/bytearray?
Uchitha
Uchitha - unfortunately no. It is just in the nature of most modern encryption algorithms that they expand the encrypted string in this way. You *might* try a zip-type algorithm on the result. However, I think that you'd find that the shrinkage would be minimal due to the nature of the encryption output. I have to admit though - I'm not sure of this as I've never tried it. I just seem to remember reading somewhere that there is little compression to be had.
Mark Brittingham
Let's say one wanted to add salting to this how would one go about it? :-p
Chris
Mark, you shouldn't use words like "above" in your answer since the answers move around in relation to each other. In fact, the only thin above this answer in vote order is the question.
paxdiablo
@paxdiablo - you are right, of course. However, when I wrote this, ZeroBugBounce (I think) was the "selected answer."
Mark Brittingham
Nice - note that you could use Convert.ToBase64String and Convert.FromBase64String to get a more compact string representation in your EncryptString and DecryptString methods (rather than your hand-rolled StrToByteArray and ByteArrayToStr methods)
zcrar70
A: 

A very simple, easy two-way encrytpion is XOR encryption. 1) Come up with a password. Let's have it be mypass.
2) Convert the password into binary (according to ASCII). The password becomes 01101101 01111001 01110000 01100001 01110011 01110011.
3) Take the message you want to encode. Convert that into binary, also.
4) Look at the length of the message. If the message length is 400 bytes, turn the password into a 400 byte string by repeating it over and over again. It would become 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011 01101101 01111001 01110000 01100001 01110011 01110011... (or mypassmypassmypass...)
5) XOR the message with the long password.
6) Send the result.
7) Another time, XOR the encrypted message with the same password (mypassmypassmypass...).
8) There's your message!

stalepretzel
XOR - Seriously?
Ryan
+3  A: 

I found Mark Brittingham's answer above really helpful when I was doing this in .Net 3.5, so I figured I'd post what I did, too.

I followed Mark's example to figure this out, but I used the new AesManaged class available in .Net 3.5, and took advantage of the ICryptoTransform interface to abstract the meat of it into one method that does both the encryption and the decryption.

Swap in your own key and iv, and your favorite encoding method (if you don't want Unicode), and you're good to go:

    public string encryptString(String dataString)
    {
        AesManaged aes = new AesManaged();
        ICryptoTransform encryptor = aes.CreateEncryptor(key, iv);
        String encryptedString = performCryptoAndEncoding(dataString, encryptor);
        return encryptedString;
    }

    public string decryptString(String dataString)
    {
        AesManaged aes = new AesManaged();
        ICryptoTransform decryptor = aes.CreateDecryptor(key, iv);
        String decryptedString = performCryptoAndEncoding(dataString, decryptor);
        return decryptedString;
    }

    private string performCryptoAndEncoding(string dataToEncryptOrDecrypt, ICryptoTransform transform)
    {
        byte[] encodedData = encodeStringToBytes(dataToEncryptOrDecrypt);

        MemoryStream dataStream = new MemoryStream();
        CryptoStream encryptionStream = new CryptoStream(dataStream, transform, CryptoStreamMode.Write);

        encryptionStream.Write(encodedData, 0, encodedData.Length);
        encryptionStream.FlushFinalBlock();
        dataStream.Position = 0;

        byte[] transformedBytes = new byte[dataStream.Length];
        dataStream.Read(transformedBytes, 0, transformedBytes.Length);
        encryptionStream.Close();
        dataStream.Close();

        String transformedAndReencodedData = encodeBytesToString(transformedBytes);
        return transformedAndReencodedData;
    }

    private byte[] encodeStringToBytes(string dataToEncode)
    {
        byte[] encodedData = Encoding.Unicode.GetBytes(dataToEncode);
        return encodedData;
    }

    private string encodeBytesToString(byte[] dataToEncode)
    {
        String encodedData = Encoding.Unicode.GetString(dataToEncode, 0, dataToEncode.Length);
        return encodedData;
    }

EDIT: Apparently the Unicode encoding in my code above breaks for some characters. I guess it's time for me to learn more about encoding. Here's a more fail-safe way to encode/decode from byte[] to string:

   private byte[] encodeStringToBytes(string dataToEncode)
    {
        List<byte> bytes = new List<byte>();
        foreach (char character in dataToEncode.ToCharArray())
        {
            bytes.Add((byte)character);
        }
        return bytes.ToArray();
    }

    private string encodeBytesToString(byte[] dataToEncode)
    {
        String encodedString = "";
        foreach (byte bite in dataToEncode)
        {
            encodedString = encodedString + (char)bite;
        }
        return encodedString;
    }
Chris Jaynes
I liked your answer, but I don't know how long they key of vector should be.
Praesagus