3

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();
        }
    }
}
bdndk
  • 33
  • 3
  • I don't suppose you are using Azure? Blob storage can automatically encrypt files and Azure KeyVault is a solution to where to store the encryption keys. – Crowcoder Mar 12 '17 at 19:54
  • Nope, not Azure I'm afraid. – bdndk Mar 12 '17 at 20:02
  • If the server can fully decrypt the files without any additional input data provided by the client then all you're doing is adding I/O and CPU costs to retrieval. It's not protection in any meaningful way. – Damien_The_Unbeliever Mar 13 '17 at 12:58
  • You're absolutely right, @Damien_The_Unbeliever. It's really only making sure that people with access to the server can't open the files directly. – bdndk Mar 13 '17 at 17:08

2 Answers2

4

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?

Community
  • 1
  • 1
Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Very good answer - thank you very much. I'll check out the OWASP. And also change to PKCS7 padding. And you're right. My setup doesn't really add much security, since the encryption and decryption happens without the user knowing. So the real security concern is probably the website around all of this, since it could be broken or accidentally serve a file to the wrong person. – bdndk Mar 13 '17 at 17:12
2
  1. Rfc2898DeriveBytes is essentially PBKDF2 which is NIST recommended.

  2. IF you randomize the salt (a good security practice) would will have top supply it for decryption. A common way is to prefix the encrypted data with the salt and IV.

  3. Yes, you should be using a Mac over the encrypted data and any prepended information such as above.

  4. In order to provide suggestions on securing the encryption key more information on how the the encryption will be used.

  5. Use PKCS#7 padding, sometimes the option is named PKCS#5 for historical reasons.

zaph
  • 111,848
  • 21
  • 189
  • 228
  • Good answer, thank you very much. An additional question: Why isn't it a security flaw to add salt and IV in clear text to the encrypted file data? I know that hashing passwords with a salt is not the same as this, but when hashing you want to keep the salt a secret at all cost, right? – bdndk Mar 13 '17 at 17:18
  • Having either the salt or IV does not help in breaking an encrypted message, the key is the security. – zaph Mar 13 '17 at 18:06