将CryptoStream解密为MemoryStream

Rub*_*aus 0 c# encryption aes cryptostream azure-storage-blobs

我已经编写了一个过程,在该过程中,将文件加密并上传到Azure,然后必须对下载过程进行解密,否则将失败,并显示“填充无效且无法删除”错误,或者“要解密的数据长度为无效。” 错误。

我已经尝试了许多在线解决方案,包括使用RijndaelManaged和CryptoStream解密C#mp3文件,但是它们似乎都不起作用,我最终只是在这两个错误之间来回跳动。加密过程使用的是解密使用的相同密钥/ IV对,并且由于它将解密一部分流,因此我感觉工作正常-最终会死于上述错误。

这是我的代码,有什么想法吗?请注意,三个变种(cryptoStream.CopyTo(decryptedStream)do {}while)不跑起来-他们在这里展示我已经尝试过的选项,所有这一切的失败。

byte[] encryptedBytes = null;

using (var encryptedStream = new MemoryStream())
{
    //download from Azure
    cloudBlockBlob.DownloadToStream(encryptedStream);

    //reset positioning for reading it back out
    encryptedStream.Position = 0;

    encryptedBytes = encryptedStream.ConvertToByteArray();
}

//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))
                {
                    //fails here with "Length of the data to decrypt is invalid." error
                    cryptoStream.CopyTo(decryptedStream);

                    int data;

                    //fails here with "Length of the data to decrypt is invalid." error after it loops a number of times,
                    //implying it is in fact decrypting part of it, just not everything
                    do
                    {
                        data = cryptoStream.ReadByte();
                        decryptedStream.WriteByte((byte)cryptoStream.ReadByte());
                    } while (!cryptoStream.HasFlushedFinalBlock);

                    //fails here with "Length of the data to decrypt is invalid." error after it loops a number of times,
                    //implying it is in fact decrypting part of it, just not everything
                    while ((data = cryptoStream.ReadByte()) != -1)
                    {
                        decryptedStream.WriteByte((byte)data);
                    }
                }
            }
        }

        //reset position in prep for reading
        decryptedStream.Position = 0;
        return decryptedStream.ConvertToByteArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

提到的其中一项想知道是什么的注释ConvertToByteArray,这只是一个简单的扩展方法:

/// <summary>
/// Converts a Stream into a byte array.
/// </summary>
/// <param name="stream">The stream to convert.</param>
/// <returns>A byte[] array representing the current stream.</returns>
public static byte[] ConvertToByteArray(this Stream stream)
{
    byte[] buffer = new byte[16 * 1024];
    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms.ToArray();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,代码从未达到这一点-它在我到达这一点之前就死了。

Rub*_*aus 5

经过各种博客的来回反复讨论后,我发现上面的代码中确实存在一些错误,这些错误使我感到困惑。首先,加密过程错误地写入了数组-它被CryptoStream实例包裹,但实际上并没有利用它,因此我将未加密的数据写入了Azure。这是进行此操作的正确方法(这fileKey是我创建的用于生成Key / IV对的自定义类的一部分,因此可以将引用的任何位置更改为内置过程,RijndaelManaged也可以将其用作其他用途(带有密钥/ IV对):

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

其次,由于我的加密过程涉及多个步骤(每个文件共三个密钥-容器,文件名和文件本身),所以当我尝试解密时,我使用的是错误的密钥(上面提到blobKey解密时可以看到该密钥,实际上是用于加密文件名而不是文件本身的密钥正确的解密方法是:

//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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经研究过Azure加密扩展(http://www.stefangordon.com/introducing-azure-encryption-extensions/),但它比本地文件中心要多,比我感兴趣的多-我的一切都是流/ in-memory,并且对该实用程序进行改造将比其值得的工作更多。

希望这可以帮助希望以零依赖底层文件系统加密Azure Blob的任何人!