将流加密方法从.NET转换为RT [英] Converting stream encryption method from .NET to RT
问题描述
我正在尝试将加密/解密方法从托管的.NET转换为WinRT版本,以便在Windows Store应用中使用.托管.NET加密方法已经在生产中大量使用,因此可以假设它们可以正常工作.
I'm trying to convert Encryption/Decryption methods from managed .NET to WinRT version for use in Windows Store app. The managed .NET encryption methods are already used largely in production, so the assumption is they work correctly.
这是托管的.NET加密方法:
This is the managed .NET encryption method:
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版本.
This is the WinRT version that uses CryptographicEngine
.
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
代码),但无济于事.
The goal is to be able to encrypt large files by reading and encrypting chunks of bytes. The problem that I have with the RT method is that everytime it encrypts a chunk, the encrypted bytes are larger by 8 bytes. I understand on the .NET side this is what CryptoStream.FlushFinalBlock()
adds.
I tried trimming the bytes to the original size (the commented finalChunk
code), but it didn't help.
如何在WinRT中可靠地进行加密,并使最终的加密文件与.NET方法生成的文件相同.
How can I reliably encrypt in WinRT and have the final encrypted file be identical with what the .NET method produces.
谢谢
推荐答案
要回答我的问题,我发现了问题.Windows运行时不支持缓冲加密,并且将始终将数据视为一个整体..NET ICryptoTransform
包含诸如 TransformBlock
和 TransformFinalBlock
之类的方法,而RT API始终使用将数据视为最终数据,从而无法对大型数据进行加密大块流.我最终使用了完美的BouncyCastle PCL库.同样,BouncyCastle中的 DesEngine
具有方法 ProcessBytes
和 DoFinal
,它们与上述 ICryptoTransform
中的.NET方法相对应.
To answer my question, I found the problem. Windows Runtime doesn't support buffered encryption and will always treat data as a whole. While the .NET ICryptoTransform
contains methods like TransformBlock
and TransformFinalBlock
, the RT API always uses treats data as final, which makes it impossible to encrypt large streams by chunks.
I ended up using BouncyCastle PCL library which worked out perfectly. Similarly, DesEngine
in BouncyCastle has method ProcessBytes
and DoFinal
which correspond to the above mentioned .NET methods in ICryptoTransform
.
希望这对某人有帮助.
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();
}
});
}
这篇关于将流加密方法从.NET转换为RT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!