将流加密方法从.net转换为RT
本文关键字:转换 RT net 加密 方法 | 更新日期: 2023-09-27 18:17:10
我正在尝试将加密/解密方法从托管。net转换为WinRT版本,以便在Windows Store应用程序中使用。托管。net加密方法已经在生产中大量使用,因此假设它们正常工作。
这是托管。net加密方法:
public static byte[] iv = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
public static void EncryptFile(string sInputFilename, string sOutputFilename, string sKey)
{
FileStream fsInput = null;
FileStream fsOutput = null;
CryptoStream cryptostream = null;
try
{
#region Prep
fsInput = new FileStream(sInputFilename, FileMode.Open, FileAccess.Read);
fsOutput = new FileStream(sOutputFilename, FileMode.Create, FileAccess.Write);
var cryptoDes = new DESCryptoServiceProvider { IV = iv, Key = Convert.FromBase64String(sKey), Mode = CipherMode.CBC };
var desEncrypt = cryptoDes.CreateEncryptor();
#endregion
cryptostream = new CryptoStream(fsOutput, desEncrypt, CryptoStreamMode.Write);
long startIndex = 0;
var bytearrayinput = new byte[64];
var byteCount = bytearrayinput.Length;
while (startIndex < fsInput.Length)
{
if (fsInput.Length - startIndex < byteCount)
{
byteCount = (int)(fsInput.Length - startIndex);
}
fsInput.Read(bytearrayinput, 0, byteCount);
cryptostream.Write(bytearrayinput, 0, byteCount);
startIndex += byteCount;
}
cryptostream.FlushFinalBlock();
}
finally
{
if (fsInput != null) { fsInput.Close(); }
if (cryptostream != null) { cryptostream.Close(); }
if (fsOutput != null) { fsOutput.Close(); }
}
}
这是使用CryptographicEngine
的WinRT版本
public static async Task EncryptContentFile(IRandomAccessStream inputStream, IRandomAccessStream outputStream, string key)
{
var iv = CryptographicBuffer.CreateFromByteArray(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 });
var keyMaterial = CryptographicBuffer.DecodeFromBase64String(key);
var cryptoProvider = SymmetricKeyAlgorithmProvider.OpenAlgorithm(SymmetricAlgorithmNames.DesCbcPkcs7);
var symmetricKey = cryptoProvider.CreateSymmetricKey(keyMaterial);
var inStream = inputStream.AsStreamForRead();
var outStream = outputStream.AsStreamForWrite();
try
{
var size = (long)inputStream.Size;
var chunkSize = 64L;
//var finalChunk = false;
while (inStream.Position < size)
{
if (size - inStream.Position < chunkSize)
{
chunkSize = size - inStream.Position;
//finalChunk = true;
}
var chunk = new byte[chunkSize];
await inStream.ReadAsync(chunk, 0, (int)chunkSize);
var writeBuffer = CryptographicEngine.Encrypt(symmetricKey, chunk.AsBuffer(), iv).ToArray();
await outStream.WriteAsync(writeBuffer, 0, (int)chunkSize);
//await outStream.WriteAsync(writeBuffer, 0, finalChunk ? writeBuffer.Length : (int)chunkSize);
}
await outputStream.FlushAsync();
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
}
}
目标是能够通过读取和加密字节块来加密大文件。我在RT方法中遇到的问题是,每次它加密一个块时,加密的字节都会增加8个字节。我理解在。net方面,这是CryptoStream.FlushFinalBlock()
添加的。我试图修剪字节到原来的大小(注释的finalChunk
代码),但它没有帮助。
如何在WinRT中可靠地加密,并使最终加密的文件与。net方法生成的文件相同?
谢谢
回答我的问题,我找到了问题。Windows运行时不支持缓冲加密,总是将数据作为一个整体来处理。虽然。net ICryptoTransform
包含像TransformBlock
和TransformFinalBlock
这样的方法,但RT API总是使用将数据视为final,这使得不可能按块加密大型流。我最终使用了BouncyCastle PCL库,效果很好。同样,BouncyCastle中的DesEngine
也有方法ProcessBytes
和DoFinal
,它们对应于上述ICryptoTransform
中的。net方法。
希望这能帮助到一些人。
private Task TransformStream_DesCbcPkcs7_WithProgress(bool forEncryption, Stream inputStream, Stream outputStream, byte[] key, byte[] iv, IProgress<int> progress)
{
return Task.Run(async () =>
{
// Initialize symmetric crypto engine
// Algorithm: DES
// Mode of operation: CBC
// Byte padding: PKCS#7
var engine = new PaddedBufferedBlockCipher(new CbcBlockCipher(new DesEngine()), new Pkcs7Padding());
engine.Init(forEncryption, new ParametersWithIV(new DesParameters(key), iv));
// Report progress if available
Action<int> report = x =>
{
if (progress != null)
progress.Report(x);
};
var size = inputStream.Length;
var current = inputStream.Position;
var chunkSize = 1024 * 1024L;
var lastChunk = false;
report(0);
await Task.Yield();
// Initialize DataReader and DataWriter for reliable reading and writing
// to a stream. Writing directly to a stream is unreliable.
using (var reader = new BinaryReader(inputStream))
using (var writer = new BinaryWriter(outputStream))
{
while (current < size)
{
if (size - current < chunkSize)
{
chunkSize = (uint)(size - current);
lastChunk = true;
}
var chunk = new byte[chunkSize];
reader.Read(chunk, 0, (int)chunkSize);
// The last chunk must call DoFinal() as it appends additional bytes
var processedBytes = lastChunk ? engine.DoFinal(chunk) : engine.ProcessBytes(chunk);
writer.Write(processedBytes);
current = inputStream.Position;
report((int)(current * 100F / size));
await Task.Yield();
}
await outputStream.FlushAsync();
}
});
}