我正在使用 Bouncy Castle 库来加密我的 Windows 应用商店应用程序中的一些数据。我的EncryptHelper
班级:
public static class EncryptHelper
{
private const string KEY = "chiaveAES";
private const int SIZE = 16;
private enum CipherMode
{
Encrypt,
Decrypt
}
private static PaddedBufferedBlockCipher InitCipher(CipherMode mode)
{
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new AesLightEngine()), new ZeroBytePadding());
var key = new byte[32];
var keyArray = KEY.ToCharArray();
Buffer.BlockCopy(keyArray, 0, key, 0, Math.Min(keyArray.Length, key.Length));
cipher.Init(mode == CipherMode.Encrypt, new KeyParameter(key));
return cipher;
}
public static async Task Encrypt(Stream sourceStream, Stream destinationStream, bool autoSeekStart = true, bool autoSeekEnd = true)
{
//await Process(InitCipher(CipherMode.Encrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
await ProcessBlocks(InitCipher(CipherMode.Encrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
}
public static async Task Decrypt(Stream sourceStream, Stream destinationStream, bool autoSeekStart = true, bool autoSeekEnd = true)
{
//await Process(InitCipher(CipherMode.Decrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
await ProcessBlocks(InitCipher(CipherMode.Decrypt), sourceStream, destinationStream, autoSeekStart, autoSeekEnd);
}
private static async Task Process(PaddedBufferedBlockCipher cipher, Stream sourceStream, Stream destinationStream, bool autoSeekStart, bool autoSeekEnd)
{
if (autoSeekStart)
{
sourceStream.ToBegin();
destinationStream.ToBegin();
}
var size = Convert.ToInt16(sourceStream.Length);
byte[] inBuffer = new byte[size];
byte[] outBuffer = new byte[cipher.GetOutputSize(size)];
int inCount = 0;
int outCount = 0;
try
{
inCount = await sourceStream.ReadAsync(inBuffer, 0, inBuffer.Length);
outCount = cipher.ProcessBytes(inBuffer, 0, inCount, outBuffer, 0);
outCount += cipher.DoFinal(outBuffer, outCount);
await destinationStream.WriteAsync();
await destinationStream.FlushAsync();
}
catch { }
if (autoSeekEnd)
{
sourceStream.ToBegin();
destinationStream.ToBegin();
}
}
private static async Task ProcessBlocks(PaddedBufferedBlockCipher cipher, Stream sourceStream, Stream destinationStream, bool autoSeekStart, bool autoSeekEnd)
{
if (autoSeekStart)
{
sourceStream.ToBegin();
destinationStream.ToBegin();
}
byte[] inBuffer = new byte[SIZE];
byte[] outBuffer = new byte[cipher.GetOutputSize(SIZE)];
int inCount = 0;
int outCount = 0;
try
{
while ((inCount = await sourceStream.ReadAsync(inBuffer, 0, inBuffer.Length)) > 0)
{
outCount += cipher.ProcessBytes(inBuffer, 0, inCount, outBuffer, 0);
await destinationStream.WriteAsync(outBuffer, 0, outBuffer.Length);
}
outBuffer = ?
outCount += cipher.DoFinal(outBuffer, outCount);
await destinationStream.WriteAsync(outBuffer, 0, outCount);
await destinationStream.FlushAsync();
}
catch { }
if (autoSeekEnd)
{
sourceStream.ToBegin();
destinationStream.ToBegin();
}
}
}
我的Process()
方法工作正常,但在指示时
inCount = await sourceStream.ReadAsync(inBuffer, 0, inBuffer.Length);
如果流有太多数据,我担心它可能会发生 OutOfMemoryException。因此,我试图构建该ProcessBlocks()
方法,该方法应逐步从流中读取,每次一个块,而不会对 RAM 过度充电。我对如何处理有一些疑问outBuffer
:它应该在执行 cipher.ProcessBytes() 的每个周期中被覆盖,但是在the cipher.DoFinal()
调用之前它应该是什么大小?
谢谢
2015 年 7 月 30 日更新
我修改了答案中的 Main 来处理一个 zip 文件,而输出的 zip 文件不再是一个有效的 ZIP,有人能解释一下为什么吗?
public static void Main(string[] args)
{
var plainPath = @"C:\Users\Federico\Desktop\0abed72d-defc-4c9a-a8ae-3fec43f01224.zip";
var decryptPath = @"C:\Users\Federico\Desktop\0abed72d-defc-4c9a-a8ae-3fec43f01224 - decrypted.zip";
var plainStream = new FileStream(plainPath, FileMode.Open, FileAccess.Read);
var cipherStream = new MemoryStream();
EncryptHelper.Encrypt(plainStream, cipherStream);
cipherStream.Seek(0, SeekOrigin.Begin);
FileStream fs = new FileStream(decryptPath, FileMode.Create);
EncryptHelper.Decrypt(cipherStream, fs);
fs.Flush();
fs.Close();
}