将流加密方法从.NET转换为RT [英] Converting stream encryption method from .NET to RT

查看:66
本文介绍了将流加密方法从.NET转换为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆