c# RijndaelManaged 加密和解密有时会失败
c# RijndaelManaged encryption & decryption sometimes fails
编辑:已解决 - 问题是解密功能。更正的解密函数可以在下面的答案中找到。
我在工作的最后一天试图弄清楚我在这个 AES 实现中出了什么问题。我们需要能够 encrypt/decrypt 大文件,所以我使用文件流并将每个块写入磁盘。 AES 是一项要求,因为这需要与使用 java 编写的现有系统一起使用,该系统使用 AES/CBC/PKCS5Padding(据我所知相当于 PKCS7/CBC)
此实现适用于大多数 文件。但是,有一些文件缺少原始数据的最后 5 个字节。该文件将解密而不会出现错误,但哈希值不匹配,丢失的字节是真实数据和尾随零的组合。
需要注意的是,这些流在加密前后都进行了 gzip 压缩(代码在底部)。
加密
public static void AesEncrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = 256;
const int chunkSize = 4096;//1024 * 1024 * 10;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, encryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, buffer.Length);
cryptoStream.Flush();
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}
解密
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(dataStream, decryptor, CryptoStreamMode.Read))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
cryptoStream.Read(buffer, 0, buffer.Length);
outStream.Write(buffer, 0, buffer.Length);
outStream.Flush();
}
//cryptoStream.FlushFinalBlock(); // Was throwing an exception
}
}
symmetricKey.Clear();
}
压缩(加密前)
public static void StreamCompress(Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
const int chunkSize = 4096;
using (GZipStream gzs = new GZipStream(outStream, CompressionMode.Compress))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
gzs.Write(buffer, 0, buffer.Length);
gzs.Flush();
}
}
}
解压(解密后)
public static void StreamDecompress(Stream dataStream, FileStream outStream)
{
byte[] buffer = new byte[4096];
dataStream.Position = 0;
using (GZipStream gzs = new GZipStream(dataStream, CompressionMode.Decompress))
{
for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length))
if (r > 0) outStream.Write(buffer, 0, r);
}
}
我已经回答了一些其他问题,但无法弄清楚为什么这只发生在某些文件上。失败的文件大小为 46,854,144 字节。不过,这似乎适用于更大和更小的文件。
如有任何帮助,我们将不胜感激。
问题出在我解密数据的方式上。我错误地使用了 CryptoStream。如果有人感兴趣,更新后的解密函数如下。
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, decryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
var bytesRead = dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, bytesRead);
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}
编辑:已解决 - 问题是解密功能。更正的解密函数可以在下面的答案中找到。
我在工作的最后一天试图弄清楚我在这个 AES 实现中出了什么问题。我们需要能够 encrypt/decrypt 大文件,所以我使用文件流并将每个块写入磁盘。 AES 是一项要求,因为这需要与使用 java 编写的现有系统一起使用,该系统使用 AES/CBC/PKCS5Padding(据我所知相当于 PKCS7/CBC)
此实现适用于大多数 文件。但是,有一些文件缺少原始数据的最后 5 个字节。该文件将解密而不会出现错误,但哈希值不匹配,丢失的字节是真实数据和尾随零的组合。
需要注意的是,这些流在加密前后都进行了 gzip 压缩(代码在底部)。
加密
public static void AesEncrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = 256;
const int chunkSize = 4096;//1024 * 1024 * 10;
using (ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, encryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, buffer.Length);
cryptoStream.Flush();
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}
解密
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(dataStream, decryptor, CryptoStreamMode.Read))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
cryptoStream.Read(buffer, 0, buffer.Length);
outStream.Write(buffer, 0, buffer.Length);
outStream.Flush();
}
//cryptoStream.FlushFinalBlock(); // Was throwing an exception
}
}
symmetricKey.Clear();
}
压缩(加密前)
public static void StreamCompress(Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
const int chunkSize = 4096;
using (GZipStream gzs = new GZipStream(outStream, CompressionMode.Compress))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes ? new byte[(int)remainingBytes] : new byte[chunkSize];
dataStream.Read(buffer, 0, buffer.Length);
gzs.Write(buffer, 0, buffer.Length);
gzs.Flush();
}
}
}
解压(解密后)
public static void StreamDecompress(Stream dataStream, FileStream outStream)
{
byte[] buffer = new byte[4096];
dataStream.Position = 0;
using (GZipStream gzs = new GZipStream(dataStream, CompressionMode.Decompress))
{
for (int r = -1; r != 0; r = gzs.Read(buffer, 0, buffer.Length))
if (r > 0) outStream.Write(buffer, 0, r);
}
}
我已经回答了一些其他问题,但无法弄清楚为什么这只发生在某些文件上。失败的文件大小为 46,854,144 字节。不过,这似乎适用于更大和更小的文件。
如有任何帮助,我们将不胜感激。
问题出在我解密数据的方式上。我错误地使用了 CryptoStream。如果有人感兴趣,更新后的解密函数如下。
public static void AesDecrypt(byte[] keyBytes, byte[] ivBytes, Stream dataStream, FileStream outStream)
{
dataStream.Position = 0;
outStream.Position = 0;
RijndaelManaged symmetricKey = new RijndaelManaged();
symmetricKey.Mode = CipherMode.CBC;
symmetricKey.Padding = PaddingMode.PKCS7;
symmetricKey.BlockSize = 128;
symmetricKey.KeySize = keyBytes.Length == 32 ? 256 : 128;
const int chunkSize = 4096;
using (ICryptoTransform decryptor = symmetricKey.CreateDecryptor(keyBytes, ivBytes))
{
using (CryptoStream cryptoStream = new CryptoStream(outStream, decryptor, CryptoStreamMode.Write))
{
while (dataStream.Position != dataStream.Length)
{
long remainingBytes = dataStream.Length - dataStream.Position;
var buffer = chunkSize > remainingBytes
? new byte[(int) remainingBytes]
: new byte[chunkSize];
var bytesRead = dataStream.Read(buffer, 0, buffer.Length);
cryptoStream.Write(buffer, 0, bytesRead);
}
cryptoStream.FlushFinalBlock();
}
}
symmetricKey.Clear();
}