从.NET转换流的加密方法,以RT(Converting stream encryption met

2019-10-20 15:33发布

我试图加密/解密方法,从管理的.NET转换的WinRT版本在Windows商店应用中使用。 该托管.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(); }
        }
    }

这是使用WinRT的版本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代码),但它并没有帮助。

我怎样才能可靠地加密在WinRT中,并有最终的加密文件与什么.NET方法产生相同的。

谢谢

Answer 1:

要回答我的问题,我发现这个问题。 Windows运行时不支持缓冲加密,并且将始终将数据作为一个整体。 虽然.NET ICryptoTransform包含类似方法TransformBlockTransformFinalBlock ,所述RT API总是使用数据视为最终,这使得不可能通过块大的流进行加密。 最后我用它完美地工作了BouncyCastle的PCL库。 类似地, DesEngine在BouncyCastle的具有方法ProcessBytesDoFinal其对应于在上面提到的.NET方法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();
            }
        });
    }


文章来源: Converting stream encryption method from .NET to RT