R – ASP.net rijndael decrypt – Length of data to decrypt

asp.netencryptionrijndaelrijndaelmanaged

A lot of items I've found so far have been a bit vague or … unspecific so I'm hoping to get an answer.

I've got two little methods – easy ones that look as such…

    private const string initVector = "1234567890123456";
    private const string SaltValue = "ThisIsMySaltValue";
    private const int KeySize = 256;

    public static string Encrypt(string textToEncrypt)
    {
        var rijndael = new RijndaelManaged {KeySize = KeySize};
        var salt = SaltValue.ToByteArray();
        var vector = initVector.ToByteArray();

        var rfcBytes = new Rfc2898DeriveBytes(vector, salt, 2);
        var key = rfcBytes.GetBytes(rijndael.KeySize/8);

        ICryptoTransform encrypt = rijndael.CreateEncryptor(key, vector);

        var stream = new MemoryStream();
        var data = Encoding.ASCII.GetBytes(textToEncrypt);
        stream.Write(data, 0, data.Length);

        var cryptoStream = new CryptoStream(stream, encrypt, CryptoStreamMode.Write);
        cryptoStream.Write(data, 0, data.Length);
        cryptoStream.FlushFinalBlock();

        cryptoStream.Close();
        return Convert.ToBase64String(stream.ToArray());
    }


    public static string Decrypt(string textToDecrypt)
    {
        var vector = initVector.ToByteArray();
        var salt = SaltValue.ToByteArray();
        var encrypted = textToDecrypt.ToByteArray();

        var rijndael = new RijndaelManaged {KeySize = KeySize};

        var rfcBytes = new Rfc2898DeriveBytes(vector, salt, 2);
        var key = rfcBytes.GetBytes(rijndael.KeySize/8);

        var decrypt = rijndael.CreateDecryptor(key, vector);

        var stream = new MemoryStream(encrypted);
        var cryptoStream = new CryptoStream(stream, decrypt, CryptoStreamMode.Read);

        byte[] plainBytes = new byte[textToDecrypt.Length];

        var decryptedLength = cryptoStream.Read(plainBytes, 0, plainBytes.Length);

        var plainText = Encoding.UTF8.GetString(plainBytes, 0, decryptedLength);
        return plainText;
    }

Unit Test looks something like this …

    [Test]
    public void JustTestingThisOut()
    {
        var encryptMe = "SomethingToEncrypt";
        string result = encryptMe.ConvertToEncrypted();
        result.ShouldNotEqual(encryptMe);
        string backToReadAble = result.ConvertToDecrpted();
        backToReadAble.ShouldEqual(encryptMe);
    }

ToByteArray just does a return Encoding.UTF8.GetBytes(toByte); and my test string is simple – "SomethingToEncrypt". I've went down the rabbit hole of finding this thinking that might have been the problem (Convert.ToBase64String and Convert.FromBase64String) that doesn't seem to make any difference. As for the error …

TestCase
'Tests.Encryption.EncryptionUnitTests.JustTestingThisOut'
failed:
System.Security.Cryptography.CryptographicException
: Length of the data to decrypt is
invalid. at
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[]
inputBuffer, Int32 inputOffset, Int32
inputCount)

I have the FlushFinalBlock() in there, and I THOUGHT that'd do it, but …nope, makes no difference as well. Any ideas? Things to try?

Best Answer

When encrypting, you first write data to stream, then you wrap stream with a CryptoStream and write data again, this time with encryption. Why? The decryption fails because the first thing it encounters is unencrypted data.

Print the value of the ciphertext before base64 encoding to verify this. You should see the plaintext followed by a bunch of gobbledygook that is the ciphertext.

Also, you are using the initialization vector as a password. They are definitely not the same thing, and using it like this will compromise security.

Related Topic