CryptographicEngine.Decrypt method return an error in a c# UWP app

0

I don't undrestand why this code return an error:

Data error (cyclic redundancy check). (Exception from HRESULT: 0x80070017)

because the equivalent code from Silverlight Platform does not raise an exception.This is the UWP c# code below:

public static async Task<Stream> Decrypt(Stream source,
            IBuffer easKey,IBuffer IV, byte[] masterKey)
        {
            try
            {

                SymmetricKeyAlgorithmProvider aes = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.AesCbcPkcs7);
                if ((source.Length % aes.BlockLength) != 0)
                {
                    var temp = new MemoryStream();
                    temp.SetLength(source.Length + (aes.BlockLength - source.Length % aes.BlockLength));
                    source.CopyTo(temp);
                    source = temp;
                }

                CryptographicKey symmKey = aes.CreateSymmetricKey(easKey);
                var sarray = ((MemoryStream)source).ToArray();
                IBuffer resultBuffer = CryptographicEngine.Decrypt(symmKey,sarray.AsBuffer(), IV);
                byte[] result;
                CryptographicBuffer.CopyToByteArray(resultBuffer, out result);

                return new MemoryStream(result);


            }
            catch (Exception e)
            {
                await new MessageDialog(e.StackTrace, e.Message).ShowAsync();
            }
            return null;

        }
c#
windows
visual-studio-2015
uwp
asked on Stack Overflow Aug 3, 2015 by frank_lbt

1 Answer

0

vcsjones hit an important point in the comment under your question. If you check for the data length to be an even multiple of the block length and it's not, you should throw an exception right then that the data is bad. Because nothing encrypted with AES will result in anything different from an even multiple of the block length ever. Even the empty string produces a 1-block-long cipher text.

Having said that, you have your encryption algorithm prepared to decrypt blocks with PKCS7 padding. And on the other hand, if you get a short block, you are copying it into a MemoryStream that is the correct length. I assume the last bytes are zeros. So that block is not a valid cipher text block.

PKCS7 padding adds X number of bytes to get the even multiple of the block size, and each of those bytes is that same number. So if you have a block size of 16 bytes (128 bits) and your last block only contains 10 bytes of real information, you would have the last 6 bytes padded as 0x06 0x06 0x06 0x06 0x06 0x06.

Critical here, though, is that this padding is added to the plain text before encryption. You cannot simply add the padding to the end of a partial block of cipher text and be able to decrypt it. It is the nature of these strong encryption algorithms that the final value of any given bit in the block is a function of literally every other bit in the block. So if you lost any portion of that block, you lost the whole block irretrievably.

Now if you really need to decrypt as much of the message as you can, throw away the partial block (you'll never decrypt it anyway as I mentioned above). Replace it with a full block of 0x10 (repeated 16 times). This tells the algorithm that you had exactly X number of blocks of plain text and, per PKCS7, you added exactly an entire block of PKCS7-compliant padding. This will allow you to decrypt all but the partial block of the message.

Editing to say you should encrypt the padding block using the same key and tack it to the cipher text to be able to decrypt all but the partial block. But that is not the easiest way anyway. In your place I would just change my decrypt settings to padding = None. Again throw away the partial block, and the rest should decrypt without a problem as long as it is not corrupted.

answered on Stack Overflow Aug 3, 2015 by WDS

User contributions licensed under CC BY-SA 3.0