简体   繁体   中英

CryptoStream Throws Error When Closing on Decryption

I'm trying to encrypt a plain text using RijndaelManaged class and then decrypt the encrypted string to have the same plain text in the end.

Everything is okay while ecrypting the plain text as below,

    protected static string AESEncrypt(string plainText, string key)
    {
        byte[] encryptedBytes = null;

        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;

                var keyHold = new Rfc2898DeriveBytes(key, saltBytes, 1000);

                aes.Key = keyHold.GetBytes(aes.KeySize / 8);
                aes.IV = keyHold.GetBytes(aes.BlockSize / 8);

                aes.Mode = CipherMode.CBC;

                var bytesToBeEncrypted = Encoding.UTF8.GetBytes(plainText);

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

                encryptedBytes = ms.ToArray();
            }
        }

        return Convert.ToBase64String(encryptedBytes);
    }

For instance, i'm encrypting this plain text "encryptMe" via calling above mentioned function as var encryptedString = AESEncrypt(plainText, "lockMe"); . The result is nKytZ86r0DDKSzD3ph+ntg== .

Then I send that encrypted string to below mentioned fucntion,

    protected static string AESDecrypt(string cryptedText, string key)
    {
        byte[] decryptedBytes = null;

        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;

                var keyHold = new Rfc2898DeriveBytes(key, saltBytes, 1000);

                aes.Key = keyHold.GetBytes(aes.KeySize / 8);
                aes.IV = keyHold.GetBytes(aes.BlockSize / 8);

                aes.Mode = CipherMode.CBC;

                var bytesToBeDDecrypted = Encoding.UTF8.GetBytes(cryptedText);

                using (var cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(bytesToBeDDecrypted, 0, bytesToBeDDecrypted.Length);
                    cs.Close();
                }

                decryptedBytes = ms.ToArray();
            }
        }

        return Encoding.UTF8.GetString(decryptedBytes);
    }

On this method, code throws an error The input data is not a complete block while leaving CryptoStream .

My KeySize and BlockSize are both divisible by 8 and I can't see what I have overlook.

In AESDecrypt you have:

var bytesToBeDDecrypted = Encoding.UTF8.GetBytes(cryptedText);

Since you are passing base-64 encoded cipher this should instead be

var bytesToBeDDecrypted = Convert.FromBase64String(cryptedText);

There are also some security improvements you should make. You should increase the iteration count from 1000 to something much larger, 65K at least. The salt should be at least 12 bytes and should be generated randomly for each encryption. It does not need to be kept secret, it's usually convenient to prepend it to the cipher. The decrypter then extracts the salt from the passed-in ciphertext. You should also use a Message Authentication Code (MAC) to prevent tampering. Note that AES-GCM mode as well as some other modes include this MAC as an integral part of their operation. However, if AES-GCM is unavailable then HMAC-SHA256 likely will be and is acceptable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM