Decrypting CryptoStream into MemoryStream

前端 未结 2 1999
粉色の甜心
粉色の甜心 2021-01-15 03:01

I have written a process where a file is encrypted and uploaded to Azure, then the download process has to be decrypted which is what fails with a \"Padding is invalid and

相关标签:
2条回答
  • 2021-01-15 03:27

    After a lot of back and forth from various blogs, I found I actually had a couple of errors in the above code that were nailing me. First, the encryption process was incorrectly writing the array - it was wrapped with a CryptoStream instance, but wasn't actually utilizing that so I was writing the unencrypted data to Azure. Here is the proper route to go with this (fileKey is part of a custom class I created to generate Key/IV pairs, so wherever that is referenced can be changed to the built-in process from RijndaelManaged or anything else you'd utilize for coming up with a key/IV pair):

    using (var aes = new RijndaelManaged { KeySize = 256, Key = fileKey.Key, IV = fileKey.IV })
    {
        using (var encryptedStream = new MemoryStream())
        {
            using (ICryptoTransform encryptor = aes.CreateEncryptor())
            {
                using (CryptoStream cryptoStream = new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write))
                {
                    using (var originalByteStream = new MemoryStream(file.File.Data))
                    {
                        int data;
                        while ((data = originalByteStream.ReadByte()) != -1)
                            cryptoStream.WriteByte((byte)data);
                    }
                }
            }
    
            var encryptedBytes = encryptedStream.ToArray();
            return encryptedBytes;
        }
    }
    

    Second, since my encryption process involves multiple steps (three total keys per file - container, filename and file itself), when I tried to decrypt, I was using the wrong key (which is seen above when I referenced blobKey to decrypt, which was actually the key used for encrypting the filename and not the file itself. The proper decryption method was:

    //used for the blob stream from Azure
    using (var encryptedStream = new MemoryStream(encryptedBytes))
    {
        //stream where decrypted contents will be stored
        using (var decryptedStream = new MemoryStream())
        {
            using (var aes = new RijndaelManaged { KeySize = 256, Key = blobKey.Key, IV = blobKey.IV })
            {
                using (var decryptor = aes.CreateDecryptor())
                {
                    //decrypt stream and write it to parent stream
                    using (var cryptoStream = new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read))
                    {
                        int data;
    
                        while ((data = cryptoStream.ReadByte()) != -1)
                            decryptedStream.WriteByte((byte)data);
                    }
                }
            }
    
            //reset position in prep for reading
            decryptedStream.Position = 0;
            return decryptedStream.ConvertToByteArray();
        }
    }
    

    I had looked into the Azure Encryption Extensions (http://www.stefangordon.com/introducing-azure-encryption-extensions/), but it was a little more local file-centric than I was interested - everything on my end is streams/in-memory only, and retrofitting that utility was going to be more work than it was worth.

    Hopefully this helps anyone looking to encrypt Azure blobs with zero reliance on the underlying file system!

    0 讨论(0)
  • 2021-01-15 03:28

    Bit late to the party, but in case this is useful to someone who finds this thread:

    The following works well for me.

    internal static byte[] AesEncryptor(byte[] key, byte[] iv, byte[] payload)
        {
            using (var aesAlg = Aes.Create())
            {
                aesAlg.Mode = CipherMode.CBC;
    
                aesAlg.Padding = PaddingMode.PKCS7;
    
                var encryptor = aesAlg.CreateEncryptor(key, iv);
    
                var encrypted = encryptor.TransformFinalBlock(payload, 0, payload.Length);
    
                return iv.Concat(encrypted).ToArray();
            }
        }
    

    and to decrypt:

    internal static byte[] AesDecryptor(byte[] key, byte[] iv, byte[] payload)
        {
            using (var aesAlg = Aes.Create())
            {
                aesAlg.Mode = CipherMode.CBC;
    
                aesAlg.Padding = PaddingMode.PKCS7;
    
                var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
    
                return decryptor.TransformFinalBlock(payload, 0, payload.Length);
            }
        }
    

    this works for encrypting/decrypting both fixed length hex strings when decoded from hex to byte[] as well as utf8 variable length strings when decoded using Encoding.UTF8.GetBytes().

    0 讨论(0)
提交回复
热议问题