• 0

C# best encryption method for in-house data?


Question

Hey guys, what method would you use to encrypt data in your program? For example I have an xml file stored locally that I would like to encrypt based on a password. I would really like to explore a strong method that uses a password the end-user types in and it encrypts everything based off of what they entered. Also what are other good encryption methods

for data?

Link to comment
Share on other sites

12 answers to this question

Recommended Posts

  • 0

I often use the MS crypto API

VB example:

Be aware that the "Me.Passkey" is a property of my class.

Imports System.Security.Cryptography

Public Function EncryptString(ByVal sInput As String) As String

Dim sReturn As String = sInput

Try

Dim bKey() As Byte

Dim bPlainText() As Byte

Dim bEncoded() As Byte

Dim objMemoryStream As New MemoryStream

Dim objRijndaelManaged As New RijndaelManaged

sInput = sInput.Replace(vbNullChar, String.Empty)

bPlainText = Encoding.UTF8.GetBytes(sInput)

bKey = ConvertKeyToBytes(Me.PassKey)

Dim objCryptoStream As New CryptoStream(objMemoryStream, _

objRijndaelManaged.CreateEncryptor(bKey, mbIV), _

CryptoStreamMode.Write)

objCryptoStream.Write(bPlainText, 0, bPlainText.Length)

objCryptoStream.FlushFinalBlock()

bEncoded = objMemoryStream.ToArray

sReturn = Convert.ToBase64String(bEncoded)

'Cleanup

objMemoryStream.Close()

objCryptoStream.Close()

objMemoryStream.Dispose()

objCryptoStream.Dispose()

objMemoryStream = Nothing

objCryptoStream = Nothing

Catch ex As Exception

LogException(ex)

Finally

EncryptString = sReturn

End Try

End Function

Link to comment
Share on other sites

  • 0

The .NET framework has support for AES encryption, which is considered by most to be the current best all-around encryption algorithm if you are encrypting data using a password. Take a look at the AesCryptoServiceProvider Class on MSDN. There is example code in the community content section at the bottom.

Link to comment
Share on other sites

  • 0

I like what I hear about AES but I don't see anyway of actually putting a user-input password into it. For example program a has company information on it. I want company a to be able to input a password (that they create themselves it could be joe or str1!506 as the password, etc)

and then have the program encrypt the data it contains with that password so only they can decrypt it by entering it in.

EDIT: sorry I'm new to encryption if anyone is wondering where this is coming from :(

Link to comment
Share on other sites

  • 0

If you're new to encryption, it means that you can get about 100 things wrong. Even the experts screw it up (just look at how the PS3's ECDSA private encryption keys were just discovered through a subtle flaw in their code).

What you want is called password-based encryption (PBE). For some reason, the .NET Framework still doesn't have a built-in PBE class, though you can use the BouncyCastle library or easily roll your own (I'll provide an example class lower in this post). Unfortunately, BouncyCastle's documentation absolutely sucks.

AES, operating in CBC mode (the most common), requires 3 things: the data to be encrypted/decrypted, the encryption key, and the IV. Below is a simple C# function that can both encrypt and decrypt data using a supplied key and IV:

byte[] DoCryptoOperation(byte[] inputData, byte[] key, byte[] iv, bool encrypt)
{
    byte[] output;

    using (var aes = new AesCryptoServiceProvider())
    using (var ms = new MemoryStream())
    {
        var cryptoTransform = encrypt ? aes.CreateEncryptor(key, iv) : aes.CreateDecryptor(key, iv);

        using (var cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
            cs.Write(inputData, 0, inputData.Length);

        output = ms.ToArray();
    }

    return output;
}

So all you need to do is derive a key from your password and a salt value, generate a random IV (if encrypting), and you're set.

A few pointers:

  1. Never use a password directly as an encryption key (like jameswjrose did in his example code). EVER! Instead, derive the encryption key from the password using a tested key-derivation algorithm like PBKDF2, which is available in .NET as Rfc2898DeriveBytes.
  2. Always mix in a random salt with the key-derivation function so that using the same passphrase twice results in a completely different encryption key. The salt is transmitted along with the encrypted data so that the person decrypting the data can derive the same encryption key using the salt and entered passphrase.
  3. The IV, if required (which it is in AES CBC mode), need not be secret, but it does need to be unpredictable (ie "random"). Never use the same IV to encrypt different pieces of data. This is a fatal flaw if you make that mistake with CTR and GCM modes of encryption.
  4. Use UTF8-encoding when converting an input string to an array of bytes and back. There is almost never a good reason to use ASCII-encoding, especially since the the byte values of ASCII characters is identical in UTF8. People make this mistake so often and then wonder why things don't work. If you need to store bytes as text, Base64-encode them.
  5. MOST IMPORTANT POINT: Encryption alone does not provide authenticity. In other words, if you simply encrypt your company data, someone could alter the encrypted data and your application would decrypt it just fine without knowing that the data has been tampered with. If you're OK with that, then fine, but make sure you understand the implications of it. To provide authenticity, you need to either use an authenticated cipher mode (like GCM) or calculate an HMAC authentication code of the ciphertext and verify it before decrypting (the HMAC key would also be derived from the passphrase). There's a GCM-capable AES class available on CodePlex; I believe it's written by Microsoft, but hasn't made it into the framework yet. I'm sure BouncyCastle does authenticated encryption modes as well.

Here's the full class that will do unauthenticated string encryption using 256-bit AES keys with 8-byte salt values and 2000 key-derivation iterations (20000 to 100,000 is recommended for high-security applications, but managed code is pretty slow at it). It has 2 public methods: EncryptString and DecryptString. They are self-explanatory. There is zero error-checking code contained in this class.

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace UtdUtils
{
    public static class StringEncryption
    {
        public static readonly int KeyLengthBits = 256; //AES Key Length in bits
        public static readonly int SaltLength = 8; //Salt length in bytes
        private static readonly RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

        public static string DecryptString(string ciphertext, string passphrase)
        {
            var inputs = ciphertext.Split(":".ToCharArray(), 3);
            var iv = Convert.FromBase64String(inputs[0]); // Extract the IV
            var salt = Convert.FromBase64String(inputs[1]); // Extract the salt
            var ciphertextBytes = Convert.FromBase64String(inputs[2]); // Extract the ciphertext

            // Derive the key from the supplied passphrase and extracted salt
            byte[] key = DeriveKeyFromPassphrase(passphrase, salt); 

            // Decrypt
            byte[] plaintext = DoCryptoOperation(ciphertextBytes, key, iv, false);

            // Return the decrypted string
            return Encoding.UTF8.GetString(plaintext);
        }

        public static string EncryptString(string plaintext, string passphrase)
        {
            var salt = GenerateRandomBytes(SaltLength); // Random salt
            var iv = GenerateRandomBytes(16); // AES is always a 128-bit block size
            var key = DeriveKeyFromPassphrase(passphrase, salt); // Derive the key from the passphrase

            // Encrypt
            var ciphertext = DoCryptoOperation(Encoding.UTF8.GetBytes(plaintext), key, iv, true); 

            // Return the formatted string
            return String.Format("{0}:{1}:{2}", Convert.ToBase64String(iv), Convert.ToBase64String(salt), Convert.ToBase64String(ciphertext)); 
        }

        private static byte[] DeriveKeyFromPassphrase(string passphrase, byte[] salt, int iterationCount = 2000)
        {
            var keyDerivationFunction = new Rfc2898DeriveBytes(passphrase, salt, iterationCount);  //PBKDF2

            return keyDerivationFunction.GetBytes(KeyLengthBits / 8);
        }

        private static byte[] GenerateRandomBytes(int lengthBytes)
        {
            var bytes = new byte[lengthBytes];
            rng.GetBytes(bytes);

            return bytes;
        }

        // This function does both encryption and decryption, depending on the value of the "encrypt" parameter
        private static byte[] DoCryptoOperation(byte[] inputData, byte[] key, byte[] iv, bool encrypt)
        {
            byte[] output;

            using (var aes = new AesCryptoServiceProvider())
            using (var ms = new MemoryStream())
            {
                var cryptoTransform = encrypt ? aes.CreateEncryptor(key, iv) : aes.CreateDecryptor(key, iv);

                using (var cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
                    cs.Write(inputData, 0, inputData.Length);

                output = ms.ToArray();
            }

            return output;
        }
    }
}

Link to comment
Share on other sites

  • 0

oh wow, well thank you for the vast reply. I am going to re-read it more after I post this I just was amazed at the level of response you gave. I guess I really need to find an ave. to research more about encryption methods. This is all for fun right now. I just wanted to know

the basic of how things worked because it seems every time I read a tutorial about it they don't really explain what's going on with the IV or how the key is generated. I appreciate your post. This is enough for me to get started though.

Link to comment
Share on other sites

  • 0

every time I read a tutorial about it they don't really explain what's going on with the IV or how the key is generated.

A good starting point is PKCS #5, which is the password-based cryptography standard. Download the PDF and give it a read. It's not very long and gives a description of all the parameters and how/why they are used. The NIST also has a website devoted to cryptographic implementations; it's very useful if you can figure out how to navigate the site. I didn't understand elliptic curve cryptography until I read some documents from there. Turns out it's pretty simple. Just keep in mind that most of the example code out there on the internet is doing things wrong or using old methods. Be careful.
Link to comment
Share on other sites

  • 0

Thanks guys. I will download that PDF when I get home from work and play around with it as well. I'll make sure to be weary of trusting examples. It seems like this will take a long time of dedication to master,

which is fine by me, I love learning new topics in programming. I'll have something new to explore for a while :)

Link to comment
Share on other sites

  • 0

As a quick question I noticed that documentation stated copyright 1991-1999. Doesn't that mean the method is outdated and less secure? I've heard in my brief research older methods are really easy to crack these days. Don't get me wrong I still will read it and try it as a learning experience

but I'm guessing I wouldn't want to use the PKCS method in a production environment?

Link to comment
Share on other sites

  • 0

As a quick question I noticed that documentation stated copyright 1991-1999. Doesn't that mean the method is outdated and less secure? I've heard in my brief research older methods are really easy to crack these days. Don't get me wrong I still will read it and try it as a learning experience

but I'm guessing I wouldn't want to use the PKCS method in a production environment?

These algorithms aren't something you can just pull out of a hat when you need a new one, they take time to develop and be accepted and if anything else a newer algorithm hasn't been tested as much. It's the standard and Windows digital signatures use it, you won't have any security issues with it bar quantum computers or a major flaw being discovered (both unlikely in the next 20-30 years.)

Link to comment
Share on other sites

  • 0

In terms of .NET and encrypting passwords, you need a hashing algorithm.

There are a few supported in .NET currently, such as DES (weak), TripleDES(still a bit on the weak side), MD5 (Message Digest Algorithm, can also be cracked), SHA-256 (Secure Hashing Algorithm-256bits).

As far as I know, only SHA-256 cannot be cracked currently and is what I use when encrypting/decrypting passwords to and from a database.

Hope this helps :)

Link to comment
Share on other sites

  • 0

As far as I know, only SHA-256 cannot be cracked currently and is what I use when encrypting/decrypting passwords to and from a database.

That's not an encryption/decryption operation. SHA-256 doesn't need to be "cracked" into order to discover passwords; a dictionary attack will often suffice. And unless you're using thousands of iterations, SHA-256 is not good for hashing passwords. In fact, SHA-256 is faster than SHA-1 on 64-bit implementations because it can be better optimized with native 64-bit operations.

Use PBKDF2. It's a tested standard. It prevents precomputed-table attacks and can make dictionary attacks take forever. iPhone 4 uses 10,000 iterations. BlackBerry, for some stupid reason, only uses one.

Link to comment
Share on other sites

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.