Search code examples
c#asp.netencryptionrijndaelmanaged

Key, salt and IV when using Rijndael encryption


I'm working on a website, where users are able to upload files. I want to encrypt these files, in case there is some kind of security breach where access is granted to them.

When the user wants to download their files, I decrypt directly to the HTTP(S) output stream.

The files are placed on disc, and a record for each is inserted in the website database with some additional data (file name, size, file path, IV and such).

I only have a basic understanding of how to use encryption and therefore have some questions.

I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?

Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?

Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.

I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?

This is my code for encryption. Any obvious security flaws?

const int bufferSize = 1024 * 128;

Guid guid = Guid.NewGuid();
string encryptedFilePath = Path.Combine(FILE_PATH, guid.ToString());
byte[] rgbIV;

using (Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes("PASSWORD HERE", Encoding.ASCII.GetBytes("SALT HERE")))
{
    byte[] rgbKey = deriveBytes.GetBytes(256 / 8);

    using (FileStream decryptedFileStream = File.OpenRead(decryptedFilePath))
    using (FileStream encryptedFileStream = File.OpenWrite(encryptedFilePath))
    using (RijndaelManaged algorithm = new RijndaelManaged() { KeySize = 256, BlockSize = 128, Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 })
    {
        algorithm.GenerateIV();
        rgbIV = algorithm.IV;

        using (ICryptoTransform encryptor = algorithm.CreateEncryptor(rgbKey, rgbIV))
        using (CryptoStream cryptoStream = new CryptoStream(encryptedFileStream, encryptor, CryptoStreamMode.Write))
        {
            int read;
            byte[] buffer = new byte[bufferSize];
            while ((read = decryptedFileStream.Read(buffer, 0, bufferSize)) > 0)
                cryptoStream.Write(buffer, 0, read);
            cryptoStream.FlushFinalBlock();
        }
    }
}

Solution

  • I'm using Rfc2898DeriveBytes to generate the bytes for the encryption key. Is it okay to use this class? As far as I know it uses SHA1, which might no longer be secure?

    The recent efficient breakage of SHA-1 really only impacts collision resistance which is not needed for PBKDF2 (the algorithm behind Rfc2898DeriveBytes). See: Is PBKDF2-HMAC-SHA1 really broken?

    Right now I'm using the same password and salt for each encryption, but a random IV each time. Should I also be randomizing the salt and keep it in the database along with the IV? Will this give additional security?

    Maybe it will give additional security, but it certainly won't hurt to do this except if you add a bug. Source: Need for salt with IV

    Should I be using a message authentication code (MAC)? The encrypted files themselves are only stored and never transferred, so I don't know if it's necessary.

    Usually, a storage system has checks and procedures to prevent and fix data corruption. If you don't have that, then a MAC is a good way to check if the data was corrupted even if this didn't happen maliciously.

    If the end user is supposed to receive the data, they can check the MAC themselves and make sure that nobody altered the ciphertext.

    I don't really know how to best store the encryption password. I don't want to include it in my website DLL, so I'll probably have it in a file on the server somewhere that isn't in my website folder. How else could I be doing this?

    As I understand, you actually want to hold the encryption/decryption key. Anything that you can do is really obfuscation and doesn't provide any actual security. An attacker might just use the same connection to the data storage as your usual code. At best, the attacker will be slowed down a little bit. At worst, they don't even notice that the data was encrypted, because the decryption happened transparently.

    It is best to make sure that an attacker cannot get in. Go through the OWASP top 10 and try to follow the advice. Then you can do some security scanning with Nikto or hire a professional penetration tester.

    This is my code for encryption. Any obvious security flaws?

    Using PaddingMode.ISO10126 doesn't seem like a good idea. You should go with PKCS#7 padding. Source: Why was ISO10126 Padding Withdrawn?