-1
$\begingroup$

I am using the following code to encrypt and decrypt but it is taking too much time. How can I speed up this?

public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
    {
        byte[] encryptedBytes = null;

        // Set your salt here, change it to meet your flavor:
        // The salt bytes must be at least 8 bytes.
        byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = 256;
                AES.BlockSize = 128;
                AES.Padding = PaddingMode.PKCS7;
                var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 5000);
                AES.Key = key.GetBytes(AES.KeySize / 8);
                AES.IV = key.GetBytes(AES.BlockSize / 8);
                AES.Mode = CipherMode.CBC;

                using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                    cs.Close();
                }
                encryptedBytes = ms.ToArray();
            }
        }

        return encryptedBytes;
    }`

public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
    {
        byte[] decryptedBytes = null;

        // Set your salt here, change it to meet your flavor:
        // The salt bytes must be at least 8 bytes.
        byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

        using (MemoryStream ms = new MemoryStream())
        {
            using (RijndaelManaged AES = new RijndaelManaged())
            {
                AES.KeySize = 256;
                AES.BlockSize = 128;
                AES.Padding = PaddingMode.PKCS7;
                var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 5000);
                AES.Key = key.GetBytes(AES.KeySize / 8);
                AES.IV = key.GetBytes(AES.BlockSize / 8);

                AES.Mode = CipherMode.CBC;

                using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                    cs.Close();
                }
                decryptedBytes = ms.ToArray();
            }
        }
        return decryptedBytes;
    }
$\endgroup$

closed as off-topic by e-sushi Nov 11 '17 at 12:19

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Programming questions are off-topic even if you are writing or debugging cryptographic code. Unless your question is specifically about how the cryptographic algorithm, protocol or side-channel (mitigation) works, you should look into asking on Stack Overflow instead." – e-sushi
If this question can be reworded to fit the rules in the help center, please edit the question.

  • $\begingroup$ exactly how slow is this? other than the dangerous security issues, I do not see any extremely obvious issues. How long does it take to process 16 bytes of data, and how long does it take to process 16,777,216 bytes of data? $\endgroup$ – Richie Frame Nov 12 '17 at 23:40
  • $\begingroup$ Also, what type of computer (type and OS) and CPU (exact model) are you testing on? $\endgroup$ – Richie Frame Nov 12 '17 at 23:40
  • $\begingroup$ it takes nearly 209029 milliseconds to encrypt 1000KB data. and 184 ms to decrypt !! $\endgroup$ – user269156 Nov 17 '17 at 6:14
  • $\begingroup$ 209 seconds per megabyte? are you running this code on a casio calculator watch or something? My computer can process 500000KB per second, and its about 10 years old. If you look at your process, the encrypt and decrypt are identical, and thus should take the same time $\endgroup$ – Richie Frame Nov 17 '17 at 9:41
  • $\begingroup$ I know that but I dont understand why there is such time difference. I heard that AES is faster to encrypt large data volume but in my code I don't see such reflection. $\endgroup$ – user269156 Nov 19 '17 at 5:25
3
$\begingroup$

$\bbox[pink,10px]{\Large\mathbf{\color{red}{\ ALERT\ !\ }}}$     The code as shown:

  • is insecure against any motivated adversary if passwordBytes is a human-memorized password as the name suggests; problem is use of the PBKDF2 password-to-key derivation with an iteration count of only 5000, and on top of that a public constant salt (saltBytes) ;
  • lacks any comment to describe what the functions do, is not applying to the iteration count 5000 the make constant constants mantra, duplicates the definition of salt and iteration count, any of which should be cause for pink-slipping in a sound software company;
  • has an interface making it difficult to improve speed when possible, which depends heavily on the unspecified use case (if there are several consecutive uses with the same entry of passwordBytes, then keeping key or CryptoStream across uses will save a lot of time, without sizably harming security if what's kept across uses remains safe from adversaries; doing so is a basic programming technique, and is off-topic).

There's only so much speed gain possible (aside from improving the underlying implementation of crypto primitives, interpreter, or hardware, neither of which is worded in the question). Any secure cipher is bound to have slow decryption when the key is obtained from a password, and the encryption must be steadily adjusted so that this remains true despite technological progress. Otherwise, decryption is possible by brute force password search.

Note: there are safe techniques to make encryption with a password much faster than decryption, they are AFAIK little used, but there is no indication that the question is about that, so I won't develop.

Again, security must be improved, using some of the following:

  • The iteration count should be massively increased. By an obligatory XKCD, a good memorable password has 28 to 44 bits of entropy, which with 5000 PBKDF2 iterations requires an expected $5000\cdot2^{(28\text{ to }44)-1}\approx 2^{39.3\text{ to }55.3}$ hashes to break (and $2^{(28\text{ to }44)-1}$ trial decryptions, of comparatively low cost). A single GPU can exceed $2^{46}$ SHA-256 in a day (source) which is more than enough for usual passwords, GPUs are used in clusters by password crackers, and it is logical to assume state agencies and other serious actors use ASICs (at least an order of magnitude more cost efficient) when dealing with PBKDF2.
  • The salt should be random; that at least will make the cost of deciphering many messages enciphered using distinct passwords nearly proportional to the number of messages deciphered. The encryption can draw a random salt (8 bytes is fine, 16 is aplenty), and put this at start of the ciphertext for the decryption. Use of the opaque CryptoStream makes it a tad difficult to avoid the size increase, but optimizing cryptogram size likely is secondary.
  • A better key derivation algorithm should be used, making use of a large amount of RAM; this can increase the cost of brute force attack for constant time spent in legitimate use; the sate of the art is Argon2, but within the jail of the programming environment used, that won't be available; proposing something sound is nontrivial.
$\endgroup$
  • $\begingroup$ I need to make the operation faster, I do not need to increase the security of the operation $\endgroup$ – user269156 Nov 11 '17 at 11:25
  • 3
    $\begingroup$ @user269156: If that code is actually used, yes you do need to increase the security! If this is either an academic exercise or real-life code, it is imperative to fix what I criticize in the second bullet.I explain how to improve speed in the third bullet (as does the other answer), and this is a basic programming skill. $\endgroup$ – fgrieu Nov 11 '17 at 11:33
  • $\begingroup$ dont forget about the lack of MAC! $\endgroup$ – Richie Frame Nov 12 '17 at 23:39
2
$\begingroup$

You seem to be setting up everything including deriving key from password for every encryption. You probably want to at least store the derived key temporarily in memory and reuse between encryptions. (Depending on your threat model you may want to ensure certain parts of memory don't get swapped out).

$\endgroup$
  • $\begingroup$ I am concerned about the speed of encryption, not about the security right now. How can I make this faster? $\endgroup$ – user269156 Nov 11 '17 at 11:24
  • 1
    $\begingroup$ As I said extract the key derivation. So you can use the same key for the same password. $\endgroup$ – Meir Maor Nov 11 '17 at 12:19
  • $\begingroup$ Can you please mention which line should i modify? $\endgroup$ – user269156 Nov 17 '17 at 6:16
  • $\begingroup$ There are many things wrong with the code. The derive bytes is expensive(by design). It should be extracted out of this method or if you must keep the signature add a cache for mapping password&salt to key. The IV should be chosen from a secure random source for each encryption. $\endgroup$ – Meir Maor Nov 17 '17 at 6:52

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