Friday, May 6, 2011

"Length of the data to decrypt is invalid." exception during Rijndael decryption

I get "Length of the data to decrypt is invalid." exception when i try to decrypt a memory stream. I am beginner, cant figure out whats wrong. whats wrong?

public bool EncryptStream()
    {

        string password = @"myKey123"; // Your Key Here
        UnicodeEncoding UE = new UnicodeEncoding();
        byte[] key = UE.GetBytes(password);

        s_EncryptedStream = new MemoryStream();
        int NoOfBytes;
        byte[] b_Buffer = new byte[8192];

        s_MemoryStream.Seek(0, SeekOrigin.Begin);

        RijndaelManaged RMCrypto = new RijndaelManaged();

        s_CrytpoStream = new CryptoStream(s_EncryptedStream,
            RMCrypto.CreateEncryptor(key, key),
            CryptoStreamMode.Write);

        while (s_MemoryStream.Length < s_MemoryStream.Position)
        {
            NoOfBytes = s_MemoryStream.Read(b_Buffer, 0, 8192);
            s_CrytpoStream.Write(b_Buffer, 0, NoOfBytes);
        }

        s_MemoryStream.Seek(0, SeekOrigin.Begin);

        while (s_EncryptedStream.Position < s_EncryptedStream.Length)
        {
            NoOfBytes = s_EncryptedStream.Read(b_Buffer, 0, 8192);
            s_MemoryStream.Write(b_Buffer, 0, NoOfBytes);

        }
        s_CrytpoStream.Flush();
        s_CrytpoStream.Close();

        return true;

    }


    public bool DecryptStream()
    {


        string password = @"myKey123"; // Your Key Here

        UnicodeEncoding UE = new UnicodeEncoding();
        byte[] key = UE.GetBytes(password);

        int NoOfBytes;
        byte[] b_Buffer = new byte[8192];

        s_DecryptedStream = new MemoryStream();


        RijndaelManaged RMCrypto = new RijndaelManaged();

        s_CrytpoStream = new CryptoStream(s_MemoryStream,
            RMCrypto.CreateDecryptor(key, key),
            CryptoStreamMode.Read);

        s_MemoryStream.Seek(0, SeekOrigin.Begin);

        while (s_MemoryStream.Length > s_MemoryStream.Position)
        {
            NoOfBytes = s_CrytpoStream.Read(b_Buffer, 0, 8192);
            s_DecryptedStream.Write(b_Buffer, 0, NoOfBytes);
        }

        s_DecryptedStream.Seek(0, SeekOrigin.Begin);
        s_MemoryStream.Seek(0, SeekOrigin.Begin);

        while (s_DecryptedStream.Position < s_DecryptedStream.Length)
        {
            NoOfBytes = s_DecryptedStream.Read(b_Buffer, 0, 8192);
            s_MemoryStream.Write(b_Buffer, 0, NoOfBytes);

        }

        s_CrytpoStream.Flush();
        s_CrytpoStream.Close();

        return true;

    }
From stackoverflow
  • For a start, this while loop condition is never right:

    while (s_MemoryStream.Length < s_MemoryStream.Position)
    

    How can the position be beyond the length?

    Rather than using the length of a stream, the usual pattern to copy a stream is to read repeatedly until the value returned isn't positive. As you're doing that twice in this code anyway, you might as well encapsulate it:

    public static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[8192];
        int read;
        while ( (read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            output.Write(buffer, 0, read);
        }
    }
    

    It's also best to use using statements to clean up strings. Additionally, the Encoding.Unicode property means you don't have to create a new UnicodeEncoding yourself. Also, I generally find that setting the Position property is more readable than using Seek. Finally, there's no point in a method returning a value if it's always going to be true. So, your code would become:

    public void EncryptStream()
    {
        string password = @"myKey123"; // Your Key Here
        byte[] key = Encoding.Unicode.GetBytes(password);
    
        s_EncryptedStream = new MemoryStream();
        s_MemoryStream.Position = 0;
    
        RijndaelManaged RMCrypto = new RijndaelManaged();
    
        using (Stream crytpoStream = new CryptoStream(s_EncryptedStream,
            RMCrypto.CreateEncryptor(key, key),
            CryptoStreamMode.Write))
        {
            CopyStream(s_MemoryStream, cryptoStream);
        }
    
        s_MemoryStream.Position = 0;
        s_EncryptedStream.Position = 0;
        CopyStream(s_EncryptedStream, s_MemoryStream);
    }
    
    public void DecryptStream()
    {
        string password = @"myKey123"; // Your Key Here
        byte[] key = Encoding.Unicode.GetBytes(password);
    
        s_DecryptedStream = new MemoryStream();
        s_MemoryStream.Position = 0;
    
        RijndaelManaged RMCrypto = new RijndaelManaged();
    
        using (Stream crytpoStream = new CryptoStream(s_MemoryStream,
            RMCrypto.CreateDecryptor(key, key),
            CryptoStreamMode.Read))
        {
            CopyStream(cryptoStream, s_DecryptedStream);
        }
    
        s_DecryptedStream.Position = 0;
        s_MemoryStream.Position = 0;
    
        CopyStream(s_DecryptedStream, s_MemoryStream);
    }
    

    Even after amending this code, it feels like you've got way too many non-local variables here. I can't see why any of this should be in instance variables. Make the stream to be encrypted or decrypted a parameter (along with the password) and return a memory stream with the encrypted/decrypted data in, or just a byte array.

    veagles : Thanks, that was just a rough code. I have made the changes as suggested. I am still getting the same exception in CopyStream(cryptoStream, s_DecryptedStream);
    Jon Skeet : Then please post a short but complete program which demonstrates the problem. Something we can run to reproduce it.
    veagles : It worked.. It ways my mistake.. Thanks anyways.
  • You may need to call the FlushFinalBlock method on the CryptoStream after you have finished reading the input data. (ie. crytpoStream.FlushFinalBlock() after CopyStream)

    Jon Skeet : I think you *shouldn't* need to do that if you dispose of the CryptoStream - there was a bug in .NET 1.1 which meant that it didn't flush the final block then, but it was fixed in .NET 2.0.
    Sam : Ahh, ok, just me following old code examples then.
  • I have come up with a solution and I have it posted on my new Blog

    constotech.blogspot.com/2009/05/net-encryption-using-symmetricalgorithm.html

0 comments:

Post a Comment