将CryptoStream解密为MemoryStream [英] Decrypting CryptoStream into MemoryStream

查看:140
本文介绍了将CryptoStream解密为MemoryStream的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 cannot be removed" error, or a "Length of the data to decrypt is invalid." error.

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

I've tried numerous solutions online, including C# Decrypting mp3 file using RijndaelManaged and CryptoStream, but none of them seem to work and I end up just bouncing back and forth between these two errors. The encryption process uses the same key/IV pair that decryption uses, and since it will decrypt a portion of the stream I feel like that's working fine - it just ends up dying with the above errors.

这是我的代码,有什么想法吗?请注意,这三个变体( cryptoStream.CopyTo(decryptedStream) do {} 虽然)不是一起运行-它们在这里显示我已经尝试过的选项,但所有这些都失败了。

Here is my code, any ideas? Please note that the three variants (cryptoStream.CopyTo(decryptedStream), do {} and while) aren't run together - they are here to show the options I've already tried, all of which fail.

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();
    }
}

提到的其中一项评论想知道 ConvertToByteArray 是,它只是一个简单的扩展方法:

One of the comments mentioned wanting to know what ConvertToByteArray is, and it's just a simple extension method:

/// <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();
    }
}

尽管如此,代码始终无法实现-它死于我之前

The code never reaches this though - it dies before I can ever get it to this point.

推荐答案

经过各种博客的来回反复讨论之后,我发现我实际上有一个上面代码中的两个错误使我很恼火。首先,加密过程错误地写入了数组-它被包裹在 CryptoStream 实例中,但是实际上并没有利用它,因此我将未加密的数据写入了Azure。这是与此相关的正确方法( fileKey 是我创建的用于生成Key / IV对的自定义类的一部分,因此所引用的任何地方都可以更改为已构建的-在 RijndaelManaged 或其他任何您用来提供密钥/ IV对的过程中进行处理):

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;
    }
}

第二,因为我的加密过程涉及多个步骤(三个每个文件的总密钥-容器,文件名和文件本身),当我尝试解密时,我使用了错误的密钥(如上引用 blobKey 进行解密时所见,

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();
    }
}

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

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.

希望这可以帮助希望对基础文件系统零依赖地加密Azure Blob的任何人!

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

这篇关于将CryptoStream解密为MemoryStream的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆