将流加密方法从.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方法生成的文件相同?

谢谢

将流加密方法从.net转换为RT

回答我的问题,我找到了问题。Windows运行时不支持缓冲加密,总是将数据作为一个整体来处理。虽然。net ICryptoTransform包含像TransformBlockTransformFinalBlock这样的方法,但RT API总是使用将数据视为final,这使得不可能按块加密大型流。我最终使用了BouncyCastle PCL库,效果很好。同样,BouncyCastle中的DesEngine也有方法ProcessBytesDoFinal,它们对应于上述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();
            }
        });
    }