5
$\begingroup$

I am trying to wrap my head around encryption in .NET. I am trying to implement a simple solution in ASP.NET Core to encrypt a cookie containing some non-meaningful numbers to outsiders. I need to be able to read the cookie content again.

This example (http://www.saipanyam.net/2010/03/encrypt-query-strings.html) uses Rfc2898DeriveBytes and RijndaelManaged but I don't understand if Rfc2898DeriveBytes is producing a random key tied to e.g. machine key or something else.

I need to be able to move software to a new server without managing machine keys, Redis or similar (just looking for something very simple to encrypt data).

// is this random? And if so, will I be able to read cookie contents in potentially 2 years of time?
keyGenerator = new Rfc2898DeriveBytes(ENCRYPTION_KEY, SALT);
key = keyGenerator.GetBytes(32);

// entire code from link above (clean up)

public static class MyHelper
{
    private const string ENCRYPTION_KEY = "some-secret-key";

    /// The salt value used to strengthen the encryption.
    private readonly static byte[] SALT = Encoding.ASCII.GetBytes(ENCRYPTION_KEY);
    private readonly static byte[] key;
    private readonly static byte[] iv;
    private static readonly Rfc2898DeriveBytes keyGenerator;

    static MyHelper()
    {
        keyGenerator = new Rfc2898DeriveBytes(ENCRYPTION_KEY, SALT);
        key = keyGenerator.GetBytes(32);
        iv = keyGenerator.GetBytes(16);
    }

    /// Encrypts any string using the Rijndael algorithm.
    /// A Base64 encrypted string.
    public static string Encrypt(string inputText)
    {
        //Create a new RijndaelManaged cipher for the symmetric algorithm from the key and iv
        RijndaelManaged rijndaelCipher = new RijndaelManaged { Key = key, IV = iv };

        byte[] plainText = Encoding.Unicode.GetBytes(inputText);

        using (ICryptoTransform encryptor = rijndaelCipher.CreateEncryptor())
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                {
                    cryptoStream.Write(plainText, 0, plainText.Length);
                    cryptoStream.FlushFinalBlock();
                    return Convert.ToBase64String(memoryStream.ToArray());
                }
            }
        }
    }

    /// Decrypts a previously encrypted string.
    /// The encrypted string to decrypt.
    public static string Decrypt(string inputText)
    {
        RijndaelManaged rijndaelCipher = new RijndaelManaged();
        byte[] encryptedData = Convert.FromBase64String(inputText);

        using (ICryptoTransform decryptor = rijndaelCipher.CreateDecryptor(key, iv))
        {
            using (MemoryStream memoryStream = new MemoryStream(encryptedData))
            {
                using (CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
                {
                    byte[] plainText = new byte[encryptedData.Length];
                    int decryptedCount = cryptoStream.Read(plainText, 0, plainText.Length);
                    return Encoding.Unicode.GetString(plainText, 0, decryptedCount);
                }
            }
        }
    }
}
$\endgroup$

1 Answer 1

6
$\begingroup$

No, Rfc2898DeriveBytes itself represents a deterministic algorithm. Any randomness it produces comes from a combination of randomness in the password (incorrectly named ENCRYPTION_KEY in the code) and the salt (the correctly named SALT). The other input options (such as the iteration count and string encoding) are configuration options and do not add significant randomness while still altering the final result.

Generally the output of Rfc2898DeriveBytes is made random by using a random salt which is then stored with the ciphertext (or resulting password hash, if it is used for that purpose). During decryption that same salt is used as input so that the same output key material can be produced to perform the decryption.

There are ways of constructing a class instance in such a way that the salt is generated internally, e.g. Rfc2898DeriveBytes(String, int) where the final int is the salt size. That's however not used in the code that you've shown.


Notes:

  • The inaptly named Rfc2898DeriveBytes class implements PBKDF2 and therefore should have been named PBKDF2DeriveBytes or just PBKDF2.
  • As indicated, PBKDF2 operates on a password, not a key. You can directly use a key with a unique or random IV to encrypt ciphertext if you already have a key.
  • A sentence such as "just looking for something very simple to encrypt data" will make any cryptographer cringe. You either do cryptography right or you can forget about security; there is not all that much middle ground.
$\endgroup$
5
  • $\begingroup$ Hi Maarten - thanks for your elaborate answer. The code was taken from that link and I was merely trying to understand what was going on and if it could be used for encrypting cookies / reading them at a later time. And yes, I know "something simple" does not really fly well with a cryptographer. Of course, itt should be done right but any implementation should also be balanced against the potential cost/losses. In my case, those costs are very limited in case somebody cracks the algorithm. $\endgroup$
    – Sha
    Commented Sep 19, 2018 at 11:11
  • $\begingroup$ I would not use it to encrypt anything because it implicitly uses CBC mode encryption, which is vulnerable to padding oracle attacks. Not much middle ground. Use a framework and hope for the best... And you're welcome :) $\endgroup$
    – Maarten Bodewes
    Commented Sep 19, 2018 at 11:15
  • $\begingroup$ Okay (I am new to new encryption as you can probably tell). Can you recommend any framework for this sort of task? $\endgroup$
    – Sha
    Commented Sep 19, 2018 at 11:29
  • $\begingroup$ No, because I would have to review them myself. I've not used frameworks in the past because of vulnerabilities. Best you can do is to look at the popularity and independent reviews by known cryptographers. And yes, those can be tough to find. The only alternative is to hire an expert... $\endgroup$
    – Maarten Bodewes
    Commented Sep 19, 2018 at 11:34
  • $\begingroup$ Alright - thanks for all the feedback / inputs. It is very helpful. $\endgroup$
    – Sha
    Commented Sep 19, 2018 at 11:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.