我已经写了一个过程,其中一个文件被加密并上传到Azure,然后下载过程必须解密,这是失败的,并出现“填充无效且无法删除”错误,或“要解密的数据的长度无效”。错误。
我在网上尝试了许多解决方案,包括C# Decrypting mp3 file using RijndaelManaged and CryptoStream,但它们似乎都不起作用,我最终只是在这两个错误之间来回跳跃。加密过程使用与解密相同的密钥/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();
}
}其中一条评论提到想知道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();
}
}然而,代码永远不会达到这一点--我还没来得及达到这一点,它就死了。
发布于 2015-07-20 23:09:13
在各种博客来回奔波之后,我发现我在上面的代码中确实有几个错误,让我很头疼。首先,加密过程错误地写入了数组-它被包装在一个CryptoStream实例中,但实际上并没有利用它,所以我将未加密的数据写入Azure。下面是实现这一点的正确方法(fileKey是我为生成密钥/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;
}
}其次,由于我的加密过程涉及多个步骤(每个文件总共有三个密钥-容器、文件名和文件本身),所以当我尝试解密时,我使用了错误的密钥(当我引用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();
}
}我研究过Azure加密扩展(http://www.stefangordon.com/introducing-azure-encryption-extensions/),但它更多的是以本地文件为中心,而不是我感兴趣的--我这端的所有东西都是流/内存中的,而翻新这个实用程序的工作将会比它的价值更多。
希望这能帮助任何希望对底层文件系统零依赖地加密Azure blob的人!
发布于 2018-06-11 18:47:06
有点晚了,但如果这对找到这个帖子的人有用:
下面的方法对我来说很有效。
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();
}
}并解密:
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);
}
}这适用于从hex解码为byte[]时的固定长度十六进制字符串,以及使用Encoding.UTF8.GetBytes()解码时的utf8可变长度字符串。
https://stackoverflow.com/questions/31486028
复制相似问题