Crash5998
Crash5998

Reputation: 346

AES 256 bit encryption with Rfc2898DeriveBytes

I've run into a confusing use of AES with Rfc2898DeriveBytes. Here's the code that I've found....

public static string Decrypt(string encryptionKey, string cipherValue)
    {
        byte[] cipherBytes = Convert.FromBase64String(cipherValue);
        using (var encryptor = Aes.Create())
        {
            var pdb = new Rfc2898DeriveBytes(encryptionKey, new byte[] { (13 element byte array) });
            if (encryptor != null)
            {
                encryptor.Key = pdb.GetBytes(32);
                encryptor.IV = pdb.GetBytes(16);
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                    {
                        cs.Write(cipherBytes, 0, cipherBytes.Length);
                        cs.Close();
                    }
                    cipherValue = Encoding.Unicode.GetString(ms.ToArray());
                }
            }
        }
        return cipherValue;
    }

So, "cipherValue" is an encrypted string...as well as "encryptionKey". The other examples of how to use AES and Rfc2898Derive bytes don't seem to fit this code. The other examples I've seen have something very plain-text in place of the "encryptionKey" parameter up above, but those examples are usually demonstrating encryption rather than decryption.

This code is being used to decrypt a password in the config file of my application. The encryption has already been done and I have no resources available to me to tell me how it was accomplished. I'm assuming that the password was encrypted using the indicated "encryptionKey" and the salt value, along with the default 1000 iterations and the max size Key and IV.

I'm curious mostly about how the "encryptionKey" parameter figures into things. The "cipherValue" is what's being decrypted and is giving me the right output. What methodology was at work here, and what advantages, if any, does this have over the other examples I've seen?

Encryption and security aren't my strong suits yet...let me know if I've left out anything important that might shed more light on this. Thanks in advance!

Upvotes: 1

Views: 4022

Answers (1)

bartonjs
bartonjs

Reputation: 33266

RFC2898DeriveBytes is a poorly-named implementation of PBKDF2, which is defined in RFC 2898. (Part of why it's poorly named is RFC 2898 also describes the PBKDF1 algorithm, which is what PasswordDeriveBytes uses)

You can read the full algorithm in the linked RFC section, but what it does is use the password as an HMAC key, then take the HMAC of the salt and some state data, then take the HMAC of that, and of that, up to iterations HMACs.

The purpose is to take an input password (low entropy) and predictably turn it into a cryptographic key (with high entropy) in a manner that makes it hard to figure out what the original password is.

As long as all the inputs are the same, it produces the same answer. But changing any input just a little makes a wildly different answer.

If the other approaches you've seen turn the password into a key by just using Encoding.UTF8.GetBytes() (or similar), then yes: this is a better approach (it's harder to break, and it doesn't care how long your password is).

Upvotes: 1

Related Questions