即使已处理,仍然是一个“多重处置”问题

时间:2018-11-05 11:34:32

标签: c# .net ca2202

在我的一些项目中,我一直在使用一对可靠的数据加密/解密方法(加密方法粘贴在下面)。但是我一直对CA2202这个关于memoryStream对象的警告(“不要多次放置对象”)感到困惑。我相信我会以适当的方式处理此问题,但是只要在Visual Studio中运行分析,我仍然会收到警告。它从未在生产代码中引发异常,但我仍然想一劳永逸地摆脱警告。那可能吗?还是我应该忽略它?预先感谢。

public static string Encrypt(string clearText, string passPhrase, string saltValue)
{
    byte[] clearTextBytes = Encoding.UTF8.GetBytes(clearText);
    byte[] saltValueBytes = Encoding.UTF8.GetBytes(saltValue);

    Rfc2898DeriveBytes passPhraseDerviedBytes = new Rfc2898DeriveBytes(passPhrase, saltValueBytes);
    byte[] keyBytes = passPhraseDerviedBytes.GetBytes(32);
    byte[] initVectorBytes = passPhraseDerviedBytes.GetBytes(16);

    RijndaelManaged symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC };
    ICryptoTransform encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes);

    byte[] cipherTextBytes = null;
    MemoryStream memoryStream = null;
    try
    {
        memoryStream = new MemoryStream();
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
        {
            cryptoStream.Write(clearTextBytes, 0, clearTextBytes.Length);
            cryptoStream.FlushFinalBlock();
            cipherTextBytes = memoryStream.ToArray();
        }
    }
    finally
    {
        if (memoryStream != null)
        {
            memoryStream.Dispose();
        }
    }

    return Convert.ToBase64String(cipherTextBytes);
}

2 个答案:

答案 0 :(得分:1)

这是因为CryptoStream关闭了memoryStream

您正在使用构造函数

public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode)
    : this(stream, transform, mode, false) {
}

调用

public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, bool leaveOpen) {
    _stream = stream;
    _leaveOpen = leaveOpen;
    //...
}

_leaveOpen_stream稍后在Dispose

中使用
protected override void Dispose(bool disposing) {
    try {
        if (!_leaveOpen) {
            _stream.Close();
        }
        //...
    }
}

您可以删除memoryStream.Dispose();,或将true作为参数传递给CryptoStream构造函数

using (CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write, true)) { }

github source code reference

答案 1 :(得分:1)

问题在于对CryptoStream.Dispose 的调用可以调用放置在给定的流上:

protected override void Dispose(bool disposing) 
{
    try 
    {
        if (disposing) 
        {
            if (!_finalBlockTransformed) 
            {
                FlushFinalBlock();
            }
            if (!_leaveOpen) 
            {
                _stream.Close();
            }
        }
    }
    ...
}

如果您使用带有4个参数的构造函数:

CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode, bool leaveOpen)

最后一个参数确定流是否已关闭。默认情况下,依次调用Close()也会调用Dispose

public virtual void Close()
{
    /* These are correct, but we'd have to fix PipeStream & NetworkStream very carefully.
    Contract.Ensures(CanRead == false);
    Contract.Ensures(CanWrite == false);
    Contract.Ensures(CanSeek == false);
    */

    Dispose(true);
    GC.SuppressFinalize(this);
}

因此,似乎检查无法正确确定特定的Stream实现是否将被Dispose,而回过头来以为会是这种情况。

但是请注意,在大多数情况下,对MemoryStream进行两次,一次或零次处理并不重要。