Why can't I decrypt data using RijndaelManaged?

952 views Asked by At

I'm working on a program that sends and receives messages just like messengers, and I need to encrypt the message on send button and decrypt the message when received. I'm using the RijndaelManaged class and the following methods to encrypt/decrypt

 public byte[] EncryptStringToBytes(string plainText, byte[] Key, byte[] IV)
    {

        // Check arguments.
        if (plainText == null || plainText.Length <= 0)
            throw new ArgumentNullException("plainText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");
        byte[] encrypted;
        // Create an RijndaelManaged object
        // with the specified key and IV.
        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;

            // Create a decrytor to perform the stream transform.
            ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

            // Create the streams used for encryption.
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                {
                    using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                    {

                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();

                }
            }
        }


        // Return the encrypted bytes from the memory stream.
        return encrypted;

    }

And

 public string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
    {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0)
            throw new ArgumentNullException("cipherText");
        if (Key == null || Key.Length <= 0)
            throw new ArgumentNullException("Key");
        if (IV == null || IV.Length <= 0)
            throw new ArgumentNullException("Key");

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        // Create an RijndaelManaged object
        // with the specified key and IV.
        using (RijndaelManaged rijAlg = new RijndaelManaged())
        {
            rijAlg.Key = Key;
            rijAlg.IV = IV;

            // Create a decrytor to perform the stream transform.
            ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

            // Create the streams used for decryption.
            using (MemoryStream msDecrypt = new MemoryStream(cipherText))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                    {

                        // Read the decrypted bytes from the decrypting stream
                        // and place them in a string.
                        plaintext = srDecrypt.ReadToEnd();
                    }
                }
            }

        }

        return plaintext;

    }

Here's how I invoke the previous methods:

  private void SendMessage()
    {
        string str;

        System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
        str = enc.GetString(this.EncryptStringToBytes(this.txtNewMessage.Text, myRijndael.Key, myRijndael.IV ));

        if ( this.remoteClient.Connected && this.txtNewMessage.Text.Trim() != "")
        {
            this.remoteClient.SendCommand(new Proshot.CommandClient.Command(Proshot.CommandClient.CommandType.Message, this.targetIP,str));
            this.txtMessages.Text += this.remoteClient.NetworkName + ": " + this.txtNewMessage.Text.Trim()  + "//---SENT" + Environment.NewLine;
            this.txtNewMessage.Text = "";
            this.txtNewMessage.Focus();
        }
    }



  private void private_CommandReceived(object sender , CommandEventArgs e)
    {
        string str;
        byte[] byteString;


        str =  e.Command.MetaData;

        System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
        byteString = encoding.GetBytes(str);


        switch ( e.Command.CommandType )
        {
            case ( CommandType.Message ):
                if ( !e.Command.Target.Equals(IPAddress.Broadcast) && e.Command.SenderIP.Equals(this.targetIP))
                {
                    //myRijndael.Padding = PaddingMode.Zeros;
                    this.txtMessages.Text += e.Command.SenderName + ": " + this.DecryptStringFromBytes(byteString, myRijndael.Key, myRijndael.IV) + "//---Received" + Environment.NewLine;
                    if ( !this.activated)
                    {
                        if(this.WindowState == FormWindowState.Normal || this.WindowState == FormWindowState.Maximized)
                            ShareUtils.PlaySound(ShareUtils.SoundType.NewMessageReceived);
                        else
                            ShareUtils.PlaySound(ShareUtils.SoundType.NewMessageWithPow);
                        this.Flash(this.Handle , FlashMode.FLASHW_ALL , 3);
                    }
                }
                break;
        }    
    }

The problem is I'm getting exception when decrypting Cryptographic Exception - Length of the data to decrypt is invalid, I can't figure out why ?

1

There are 1 answers

0
horgh On

Probably you should flush your CryptoStream while encrypting before you set the encrypted byte array:

...
csEncrypt.FlushFinalBlock();
encrypted = msEncrypt.ToArray();
...

An extract from CryptoStream.FlushFinalBlock Method:

Calling the Close method will call FlushFinalBlock. If you do not call Close, call FlushFinalBlock to complete flushing the buffer. Call FlushFinalBlock only when all stream activity is complete.

Obviously, if you call Close, all data will be lost, as it will close the underlying MemoryStream as well.