Decrypt Method

Mar 29, 2012 at 10:28 PM

Hi, First off thanks for this awesome library. I'm learning a ton of stuff from it.

I was working with your Decrypt function in Utilities.Encryption.ExtensionMethods.SymmetricExtensions

I could be wrong here but I believe that your function will not always work. 

1.) When you initialize the PlainTextBytes Byte[] you are initializing the size of the array to the length of the encrypted data. so what if the unencrypted data is larger than the encrypted data?

Could this solution work better? I changed my function to use Rfc289DeriveBytes instead of PasswordDeriveBytes that your using because I'm using Silverlight which does not have it. And It's depricated in the MSDN Docs. I hope you don't mind I'm chaning your code around. I still have the disclaimer In place and am learning so much from your code. Thanks again. Anyways below you could convert your code to use the buffer, length, and decrypted memory stream variables when reading in (decrypting) data from the cryptostream

I don't know if this is the right place to post this. I couldn't find a contact page on your site. Again this is just a suggestion and thank you so much for this awesome library!

 

            Byte[]              bytes           = null;
            Byte[]              buffer          = new Byte[4096];
            Int32               length          = 0;
           
            Rfc2898DeriveBytes  derivedBytes    = new Rfc2898DeriveBytes(key, salt.ToByteArray(), iterations);

            using (symmetricAlgorithm = symmetricAlgorithm.NullCheck(new AesManaged()))
            {
                symmetricAlgorithm.KeySize      = keySize;
                symmetricAlgorithm.BlockSize    = blockSize;
                symmetricAlgorithm.Key          = derivedBytes.GetBytes(symmetricAlgorithm.KeySize / 8);
                symmetricAlgorithm.IV           = derivedBytes.GetBytes(symmetricAlgorithm.BlockSize / 8);

                using (ICryptoTransform cryptoTransform = symmetricAlgorithm.CreateDecryptor())
                {
                    using (MemoryStream memoryStream = new MemoryStream(data))
                    {
                        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Read))
                        {
                            using (MemoryStream decrypted = new MemoryStream())
                            {
                                while ((length = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
                                {
                                    decrypted.Write(buffer, 0, length);
                                }

                                cryptoStream.Close();

                                bytes           = decrypted.ToArray();
                            }
                        }
                    }
                }
            }

            return bytes;

 

Mar 29, 2012 at 10:38 PM

Here is an example what your function would look like updated.

public static byte[] Decrypt(this byte[] Data, string Key, SymmetricAlgorithm AlgorithmUsing = null, string Salt = "Kosher",
                                        string HashAlgorithm = "SHA1", int PasswordIterations = 2, string InitialVector = "OFRna73m*aze01xY", int KeySize = 256)
        {
            if (Data.IsNull())
                return null;

            AlgorithmUsing = AlgorithmUsing.NullCheck(new RijndaelManaged());

            Key.ThrowIfNullOrEmpty("Key");
            Salt.ThrowIfNullOrEmpty("Salt");
            HashAlgorithm.ThrowIfNullOrEmpty("HashAlgorithm");
            InitialVector.ThrowIfNullOrEmpty("InitialVector");

            using (PasswordDeriveBytes DerivedPassword = new PasswordDeriveBytes(Key, Salt.ToByteArray(), HashAlgorithm, PasswordIterations))
            {
                using (SymmetricAlgorithm SymmetricKey = AlgorithmUsing)
                {
                    SymmetricKey.Mode = CipherMode.CBC;

                    byte[] PlainTextBytes  = null;
                    byte[] Buffer = new byte[4096];
                    int ByteCount = 0;

                    using (ICryptoTransform Decryptor = SymmetricKey.CreateDecryptor(DerivedPassword.GetBytes(KeySize / 8), InitialVector.ToByteArray()))
                    {
                        using (MemoryStream MemStream = new MemoryStream(Data))
                        {
                            using (CryptoStream CryptoStream = new CryptoStream(MemStream, Decryptor, CryptoStreamMode.Read))
                            {
                                using (MemoryStream Decrypted = new MemoryStream())
                                {
                                    while ((ByteCount = CryptoStream.Read(Buffer, 0, Buffer.Length)) > 0)
                                    {
                                        Decrypted.Write(Buffer, 0, ByteCount);
                                    }

                                    CryptoStream.Close();
                                    PlainTextBytes = Decrypted.ToArray();
                                    Decrypted.Close();
                                }
                            }
                            MemStream.Close();
                        }
                    }
                    SymmetricKey.Clear();

                    return PlainTextBytes;
                }
            }
        }
Mar 31, 2012 at 9:07 PM

Hey, a couple of things:

1) I use the MIT license in the code because I want people to modify it. I want people to be able to pull parts out, make modifications, slap it into their code base, etc. I mean don't copy it verbatim and call it your own, but I'm all for people using it however they want (and if people happen to pimp out my library, putting a link to the repository, then so much the better). Heck, I even accept pull requests/patches (you know, the few that I've received).

2) I don't do much Silverlight work. Actually, I don't do it at all. I do some WPF from time to time, but no SL. So you may run into parts of the library that will not work. I don't know what parts those might be though.

3) PasswordDeriveBytes, when I initially wrote the code that become what's actually in the library wasn't deprecated at the time. And, even though I'm pretty open to introducing breaking changes if it results in better code, I try not to do anything that will abandon legacy data. And if you run the app below:

        static void Main(string[] args)
        {
            using (Rfc2898DeriveBytes Bytes1 = new Rfc2898DeriveBytes("Password", new byte[] { 1, 2, 3, 4, 5,6,7,8 }, 2))
            {
                using (PasswordDeriveBytes Bytes2 = new PasswordDeriveBytes("Password", new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }, "SHA1", 2))
                {
                    foreach (byte x in Bytes1.GetBytes(32))
                    {
                        Console.Write((char)x);
                    }
                    Console.WriteLine();
                    foreach (byte x in Bytes2.GetBytes(32))
                    {
                        Console.Write((char)x);
                    }
                    Console.WriteLine();
                    Console.ReadLine();
                }
            }
        }

You'll notice that the keys generated are vastly different. Different keys means different encrypted data that gets spit out, which means that anything that was encrypted using the old code wouldn't work with the new code. Then I get irate emails. I try to avoid that. But I do have an idea that might be able to accommodate "upgrading" someone's code as the Rfc2898DeriveBytes uses PBKDF2, which is a bit more secure...

4)  As far as I know, none of the SymmetricAlgorithm items in .Net will produce encrypted data that is shorter than original string. That being said, it's probably a good idea, just in case. However, to make my life easier, I'm just going to write a couple of Stream extensions to handle this for me (ReadAll and ReadAllBinary). So the code is going to be a little different from the above, but should still solve the problem when I check it in.