2

I am trying to encrypt and decrypt a stream (a PDF document at base), but I am having issues with this. When I try to open the document after decryption and download, I get the error Failed to load the PDF document.

Do you know why this might be happening?

Here is the code for encryption:

public EncryptResult EncryptStream(Stream dataStream, bool reuseIV = false)
    {
        RijndaelManaged crypto = new RijndaelManaged();
        crypto.Key = _key;

        if (!reuseIV || _iv == null)
        {
            // make a copy of the current IV
            _iv = crypto.IV;
        }
        else
        {
            // reuse the previous IV
            crypto.IV = _iv;
        }

        var result = new EncryptResult() { IV = crypto.IV };

        using (var encryptor = crypto.CreateEncryptor())
        {
            using (MemoryStream msEncrypt = new MemoryStream())
            {
                using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
               {
                    var byteArrayInput = new byte[dataStream.Length];
                    dataStream.Read(byteArrayInput, 0, byteArrayInput.Length);
                    csEncrypt.Write(byteArrayInput, 0, byteArrayInput.Length);
                    dataStream.Close();

                    result.Cipher = msEncrypt.ToArray();

                    msEncrypt.Flush();
                    msEncrypt.Position = 0;

                    return result;
                }
            }
        }
    }

and decryption:

public Stream DecryptStream(byte[] cipher, byte[] iv)
    {
        RijndaelManaged crypto = new RijndaelManaged();
        crypto.Key = _key;
        crypto.IV = iv;

        crypto.Padding = PaddingMode.Zeros;

        using (var decryptor = crypto.CreateDecryptor())
        {
            using (MemoryStream msDecrypt = new MemoryStream(cipher))
            {
                using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                {
                    var sOutputFilename = new MemoryStream();
                    var fsDecrypted = new StreamWriter(sOutputFilename);
                    fsDecrypted.Write(new StreamReader(csDecrypt).ReadToEnd());

                    sOutputFilename.Position = 0;
                    return sOutputFilename;
                }
            }
        }
    }

Thanks in advance.

Marius Popa
  • 564
  • 1
  • 5
  • 22
  • Downvoters, please explain? This seems to me as a perfectly legitimate question. – Hintham Nov 05 '18 at 10:19
  • 1
    Have you done any result checking other than trying to open the result in a PDF viewer? In particular, have you compared input and output? Are they approximately the same size? Have you compared the bytes themselves? Are only some wrong or all from the start? – mkl Nov 05 '18 at 11:28

2 Answers2

1
using (MemoryStream msEncrypt = new MemoryStream())
{
   using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
   {
        //var byteArrayInput = new byte[dataStream.Length];
        //dataStream.Read(byteArrayInput, 0, byteArrayInput.Length);
        //csEncrypt.Write(byteArrayInput, 0, byteArrayInput.Length);
        dataStream.CopyTo(csEncrypt);
        dataStream.Close();

        //result.Cipher = msEncrypt.ToArray();  // not here - not flushed yet
        //msEncrypt.Flush();                    // don't need this
        //msEncrypt.Position = 0;            
    }
    result.Cipher = msEncrypt.ToArray();  
    return result;
}

and in the decryptor, get rid of all the StreamReader/StreamWriter stuff. A PDF file is compressed, ie binary. But this is after the decryption so it can't be your error.

using (var decryptor = crypto.CreateDecryptor())
{
    using (MemoryStream msDecrypt = new MemoryStream(cipher))
    {
       var outputStream = new MemoryStream();

        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
        {               
            csDecrypt.CopyTo(outputStream );
        }
        outputStream .Position = 0;
        return outputStream ;
    }
}
bommelding
  • 2,969
  • 9
  • 14
  • Note that, depending on the Stream and the implementation, `dataStream.Read(byteArrayInput, 0, byteArrayInput.Length);` may not read `byteArrayInput.Length` bytes. That is why it returns a value. – President James K. Polk Nov 05 '18 at 15:08
  • 1
    Agreed, I copied that form the question Probably not the root problem here. Fixed it now. – bommelding Nov 05 '18 at 15:13
0

One issue is, you are likely encrypting excess bytes at the end of your stream, you need to work out how many bytes are read or use

Stream.CopyTo Method

Reads the bytes from the current stream and writes them to another stream.

TheGeneral
  • 79,002
  • 9
  • 103
  • 141