1

I have an application that needs to encrypt data which is then stored in files. This data should be encrypted to an industry standard such as AES. The data may be either text or binary data.

Rather than store the key somewhere, the user should supply an alphanumeric password (used as the key) to decrypt the data.

What is the best way to go about this in C# .NET 3.5? Ideally I am looking for a black box class that I can use like so:

byte[] writeThisToFile = EncryptionClass.Encrypt(string data, string password);

byte[] writeThisToFile = EncryptionClass.Encrypt(byte[] data, string password);

byte[] plainBinaryData = EncryptionClass.DecryptBinary(byte[] encryptedFileContents, string password);

string plainText = EncryptionClass.DecryptText(byte[] encryptedFileContents, string password);
ose
  • 4,065
  • 2
  • 24
  • 40
  • Already built into .net 3.5. And this question is almost a duplicate of: http://stackoverflow.com/questions/3683277/aes-encryption-and-c-sharp – Warren P Feb 19 '12 at 02:59
  • http://msdn.microsoft.com/en-us/library/system.security.cryptography.aescryptoserviceprovider.aspx – GSerg Feb 19 '12 at 03:00
  • Check this out: http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx – Saad Imran. Feb 19 '12 at 03:01
  • 2
    +1 for using an industry standard algorithm and implementation. – Adam Liss Feb 19 '12 at 03:01
  • Thanks, I'll check it out. @WarrenP What I was looking for that was different was the user-supplied password as the key, which isn't really addressed in that question. – ose Feb 19 '12 at 03:04

3 Answers3

2

You need a "Password based key derivation function", or PBKDF2.

For AES 128, MD5 gives you the right size output, so this works as a key generation function (but keep reading) :

key = md5("MyPassw0rd!");

But it is very weak. PBKDF add many iterations of salt, something like this :

salt = "SomeValueDifferentForEachKeyGenerated";
key = md5(salt+md5(salt+md5(salt+md5(salt+"MyPassw0rd!"))));

Which is better, but still weak. MD5 is not the strongest hash algorithm around and there isn't enough iterations.

There are a good number of PBKDF functions on StackOverflow, pick one that suits you most.

Community
  • 1
  • 1
ixe013
  • 9,559
  • 3
  • 46
  • 77
2
    using System.IO;
    using System.Security;
    using System.Security.Cryptography;
    using System.Runtime.InteropServices;   

    // <summary>  
    // Encrypts a string          
    // </summary>        
    // <param name="CipherText">Text to be Encrypted</param>         
    // <param name="Password">Password to Encrypt with</param>         
    // <param name="Salt">Salt to Encrypt with</param>          
    // <param name="HashAlgorithm">Can be either SHA1 or MD5</param>         
    // <param name="PasswordIterations">Number of iterations to do</param>          
    // <param name="InitialVector">Needs to be 16 ASCII characters long</param>          
    // <param name="KeySize">Can be 128, 192, or 256</param>          
    // <returns>A decrypted string</returns>       
    public static string AESEncrypt(string PlainText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize)
    {
        if (string.IsNullOrEmpty(PlainText))
        {
            return "The Text to be Decryped by AES must not be null...";
        }
        else if (string.IsNullOrEmpty(Password))
        {
            return "The Password for AES Decryption must not be null...";
        }
        byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
        byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
        byte[] PlainTextBytes = Encoding.UTF8.GetBytes(PlainText);
        PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
        byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);

        RijndaelManaged SymmetricKey = new RijndaelManaged();

        SymmetricKey.Mode = CipherMode.CBC;

        byte[] CipherTextBytes = null;

        using (ICryptoTransform Encryptor = SymmetricKey.CreateEncryptor(KeyBytes, InitialVectorBytes))
        {

            using (MemoryStream MemStream = new MemoryStream())
            {
                using (CryptoStream CryptoStream = new CryptoStream(MemStream, Encryptor, CryptoStreamMode.Write))
                {
                    CryptoStream.Write(PlainTextBytes, 0, PlainTextBytes.Length);
                    CryptoStream.FlushFinalBlock();
                    CipherTextBytes = MemStream.ToArray();
                    MemStream.Close();
                    CryptoStream.Close();
                }
            }
        }
        SymmetricKey.Clear();
        return Convert.ToBase64String(CipherTextBytes);

    }


    // <summary>  
    // Decrypts a string          
    // </summary>        
    // <param name="CipherText">Text to be decrypted</param>         
    // <param name="Password">Password to decrypt with</param>         
    // <param name="Salt">Salt to decrypt with</param>          
    // <param name="HashAlgorithm">Can be either SHA1 or MD5</param>         
    // <param name="PasswordIterations">Number of iterations to do</param>          
    // <param name="InitialVector">Needs to be 16 ASCII characters long</param>          
    // <param name="KeySize">Can be 128, 192, or 256</param>          
    // <returns>A decrypted string</returns>        
    public static string AESDecrypt(string CipherText, string Password, string Salt, string HashAlgorithm, int PasswordIterations, string InitialVector, int KeySize)
    {
        if (string.IsNullOrEmpty(CipherText))
        {
            return "The Text to be Decryped by AES must not be null...";
        }
        else if (string.IsNullOrEmpty(Password))
        {
            return "The Password for AES Decryption must not be null...";
        }
        byte[] InitialVectorBytes = Encoding.ASCII.GetBytes(InitialVector);
        byte[] SaltValueBytes = Encoding.ASCII.GetBytes(Salt);
        byte[] CipherTextBytes = Convert.FromBase64String(CipherText);
        PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Password, SaltValueBytes, HashAlgorithm, PasswordIterations);
        byte[] KeyBytes = DerivedPassword.GetBytes(KeySize / 8);
        RijndaelManaged SymmetricKey = new RijndaelManaged();
        SymmetricKey.Mode = CipherMode.CBC;
        byte[] PlainTextBytes = new byte[CipherTextBytes.Length];
        int ByteCount = 0;
        try
        {

            using (ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(KeyBytes, InitialVectorBytes))
            {
                using (MemoryStream MemStream = new MemoryStream(CipherTextBytes))
                {
                    using (CryptoStream CryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read))
                    {
                        ByteCount = CryptoStream.Read(PlainTextBytes, 0, PlainTextBytes.Length);
                        MemStream.Close();
                        CryptoStream.Close();
                    }
                }
            }
        }
        catch (Exception e)
        {
            return "Please Enter the Correct Password and Salt..." + "The Following Error Occured: " + "/n" + e;
        }
        SymmetricKey.Clear();
        return Encoding.UTF8.GetString(PlainTextBytes, 0, ByteCount);

    }

Can't Remember exactly where I acquired this code from, but I altered it to return the encrypted Result as a string. These Methods could easily be wrapped into a FileEncryptor Class. Although I am sure there are better solutions out there...

John Bartels
  • 2,583
  • 3
  • 19
  • 26
1

you should used

byte[] writeThisToFile = EncryptionClass.Encrypt(byte[] data, string password);

byte[] plainBinaryData = EncryptionClass.DecryptBinary(byte[] encryptedFileContents, string password); 

for details read following article http://explicitcoder.in/encryption-and-decryption-methods-text-file-and-binary-files-c-net/

Brian Mains
  • 50,520
  • 35
  • 148
  • 257