重用iCryptotRansform对象



我有一个用于加密文本数据的类。我正在尝试尽可能重复使用iCryptotransform对象。但是,我第二次尝试使用同一对象时,我得到了部分解密的数据。我认为第一个块是错误的,但其余的似乎还可以(用更长的文本进行了测试(。

我将班级剥离为以下内容:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Sample.Crypto
{
    public class EncryptedStreamResolver : IDisposable
    {
        private AesCryptoServiceProvider _cryptoProvider;
        private ICryptoTransform _encryptorTransform;
        private ICryptoTransform _decryptorTransform;
        private ICryptoTransform EncryptorTransform
        {
            get
            {
                if (null == _encryptorTransform || !_encryptorTransform.CanReuseTransform)
                {
                    _encryptorTransform?.Dispose();
                    _encryptorTransform = _cryptoProvider.CreateEncryptor();
                }
                return _encryptorTransform;
            }
        }
        private ICryptoTransform DecryptorTransform
        {
            get
            {
                if (null == _decryptorTransform || !_decryptorTransform.CanReuseTransform)
                {
                    _decryptorTransform?.Dispose();
                    _decryptorTransform = _cryptoProvider.CreateDecryptor();
                }
                return _decryptorTransform;
            }
        }
        public EncryptedStreamResolver()
        {
            GenerateCryptoProvider();
        }
        public Stream OpenRead(string rawPath)
        {
            return new CryptoStream(File.OpenRead(rawPath + ".crypto"), DecryptorTransform, CryptoStreamMode.Read);
        }
        public Stream OpenWrite(string rawPath)
        {
            return new CryptoStream(File.OpenWrite(rawPath + ".crypto"), EncryptorTransform, CryptoStreamMode.Write);
        }
        private void GenerateCryptoProvider(string password = "totallysafepassword")
        {
            _cryptoProvider = new AesCryptoServiceProvider();
            _cryptoProvider.BlockSize = _cryptoProvider.LegalBlockSizes.Select(ks => ks.MaxSize).Max();
            _cryptoProvider.KeySize = _cryptoProvider.LegalKeySizes.Select(ks => ks.MaxSize).Max();
            _cryptoProvider.IV = new byte[_cryptoProvider.BlockSize / 8];
            _cryptoProvider.Key = new byte[_cryptoProvider.KeySize / 8];
            var pwBytes = Encoding.UTF8.GetBytes(password);
            for (var i = 0; i < _cryptoProvider.IV.Length; i++)
                _cryptoProvider.IV[i] = pwBytes[i % pwBytes.Length];
            for (var i = 0; i < _cryptoProvider.Key.Length; i++)
                _cryptoProvider.Key[i] = pwBytes[i % pwBytes.Length];
        }
        public void Dispose()
        {
            _encryptorTransform?.Dispose();
            _decryptorTransform?.Dispose();
            _cryptoProvider?.Dispose();
        }
    }
}

我已经编写了样本使用测试以证明问题:

public void Can_reuse_encryptor()
{
    const string message = "Secret corporate information here.";
    const string testFilePath1 = "Foo1.xml";
    const string testFilePath2 = "Foo2.xml";
    var sr = new EncryptedStreamResolver();
    // Write secret data to file
    using (var writer = new StreamWriter(sr.OpenWrite(testFilePath1)))
        writer.Write(message);
    // Read it back and compare with original message
    using (var reader = new StreamReader(sr.OpenRead(testFilePath1)))
        if (!message.Equals(reader.ReadToEnd()))
            throw new Exception("This should never happend :(");
    // Write the same data again to a different file
    using (var writer = new StreamWriter(sr.OpenWrite(testFilePath2)))
        writer.Write(message);
    // Read that back and compare
    using (var reader = new StreamReader(sr.OpenRead(testFilePath2)))
        if (!message.Equals(reader.ReadToEnd()))
            throw new Exception("This should never happend :(");
}

我想念什么?文档表明这些对象是可重复使用的,但我不明白如何使用。有人可以帮我吗?

编辑:

正如@bartonjs所指出的,如果我重新制定了我的项目,该项目包含上述代码为.NET 4.6(或以上(,我可以使用 system.appcontext.trygetsext.trygetswitch 喜欢以下:

var reuseTransform = false;
if (null == _decryptorTransform ||
    !(AppContext.TryGetSwitch("Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor", out reuseTransform) && reuseTransform && _decryptorTransform.CanReuseTransform))
{
    _decryptorTransform?.Dispose();
    _decryptorTransform = _cryptoProvider.Createdecryptor();
}

然后,我可以在主应用程序的app.config中设置此开关,如@bartonjs的答案。

您所缺少的是.net框架中的错误(和bugfix(:(。

关于同一问题的Microsoft Connect问题;具体而言,aescryptoserviceprovider.createdecryptor((返回一个说CanReuseTransform=true的对象,但似乎并未正确地行为。

该错误是在.NET 4.6.2版本中固定的,但在重新定位更改后面被保护。这意味着要查看修复程序,您需要

  1. 安装.NET框架4.6.2或更高。
  2. 将主要可执行文件的最小框架版本更改为4.6.2或更高。

如果已安装了较新的框架,但是要保持可执行的目标,以较低版本的框架,您需要将Switch Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor设置为false

来自AppContext类文档(在"备注"下(:

定义并记录了交换机后,呼叫者可以通过使用注册表,通过将AppContextSwitchoverrides元素添加到其应用程序配置文件中,或者通过以编程方式调用AppContextSwitchoverrides元素,或通过调用AppContext.setSwitch(String,boolean(方法来使用它。

用于配置文件(your.exe.config(:

<configuration>
  <runtime>
    <AppContextSwitchOverrides
      value="Switch.System.Security.Cryptography.AesCryptoServiceProvider.DontCorrectlyResetDecryptor=false" />
  </runtime>
</configuration>

相关内容

  • 没有找到相关文章

最新更新