Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何避免解密后内存中数据的未加密副本?_C#_Encryption_Persistence_Securestring - Fatal编程技术网

C# 如何避免解密后内存中数据的未加密副本?

C# 如何避免解密后内存中数据的未加密副本?,c#,encryption,persistence,securestring,C#,Encryption,Persistence,Securestring,我正在尝试编写一些函数,这些函数允许对数据块进行加密/解密。出于兼容性原因,它需要对称加密,可以保存在一台机器上,然后在另一台机器上读取,这样就排除了使用ProtectedData的可能性,因为它的范围不会比本地机器更广。太糟糕了,仅仅添加这个选项就可以节省很多麻烦 我已经做了很多网络搜索,到目前为止,我还没有遇到任何好的例子,真正尝试从磁盘上的加密值到内存中的SecureString进行干净的转换,其间没有任何痕迹。我真的很想看看如果?这是可以做到的 我有一个加密功能,它似乎工作得相当好。您给

我正在尝试编写一些函数,这些函数允许对数据块进行加密/解密。出于兼容性原因,它需要对称加密,可以保存在一台机器上,然后在另一台机器上读取,这样就排除了使用ProtectedData的可能性,因为它的范围不会比本地机器更广。太糟糕了,仅仅添加这个选项就可以节省很多麻烦

我已经做了很多网络搜索,到目前为止,我还没有遇到任何好的例子,真正尝试从磁盘上的加密值到内存中的SecureString进行干净的转换,其间没有任何痕迹。我真的很想看看如果?这是可以做到的

我有一个加密功能,它似乎工作得相当好。您给它一个SecureString,它返回一个常规字符串,其中包含SecureString内容的加密副本。如果在调用函数后保存内存转储,则无法在转储中的任何位置找到未加密数据的任何副本。这很好

然而,我没有解密对手那么幸运。虽然我可以成功地解密数据并将其返回到SecureString中,但在解密完成时,我在内存转储中得到了解密值的多个副本。当然,将副本分散在明文中会抵消使用内存加密的全部意义。这很糟糕

有人能就如何使这段代码干净,以便在代码完成后不会在内存中留下未加密值的副本提出建议吗

这是我的密码:

public SecureString Decrypt(string base64EncryptedText)
{
    using (SymmetricAlgorithm sa = GetAlgorithm())
    {
        ICryptoTransform transform = sa.CreateDecryptor();
        var result = new SecureString();
        using (var memstream = new MemoryStream())
        {
            using (var cs = new CryptoStream(memstream, transform, CryptoStreamMode.Write))
            {
                byte[] base64EncryptedTextByteArray = Convert.FromBase64String(base64EncryptedText);
                cs.Write(base64EncryptedTextByteArray, 0, base64EncryptedTextByteArray.Length);
                cs.FlushFinalBlock();  // If you don't do this, results are inconsistent from the ToArray method.

                byte[] decodedBytes = memstream.ToArray();

                // Clear the contents of the memory stream back to nulls
                memstream.Seek(0, 0);
                for (int i = 0; i < memstream.Length; i++)
                { memstream.WriteByte(0); }

                char[] decodedChars = Encoding.UTF8.GetChars(decodedBytes);

                // Null out the bytes we copied from the memory stream
                for (int i = 0; i < decodedBytes.Length; i++)
                { decodedBytes[i] = 0; }

                // Put the characters back in to the SecureString for safe keeping and null out the array as we go...
                for (int i = 0; i < decodedChars.Length; i++)
                {
                    result.AppendChar(decodedChars[i]);
                    decodedChars[i] = '\0';
                }
            }
        }
        return result;
    }
}

private SymmetricAlgorithm GetAlgorithm()
{
    string password = "DummyPassword";
    string salt = "salty";

    DeriveBytes rgb = new Rfc2898DeriveBytes(password, Encoding.Unicode.GetBytes(salt));
    SymmetricAlgorithm sa = new RijndaelManaged();
    sa.Key = rgb.GetBytes(sa.KeySize >> 3);
    sa.IV = rgb.GetBytes(sa.BlockSize >> 3);
    return sa;
}
另一件事,我还没有探索这么多,如果垃圾收集器在这一切中间运行会发生什么…如果发生这种情况,所有的赌注都被关闭了,所以在这些函数的开始运行GC来减少它在中间发生的可能性会是个好主意吗?


谢谢。

如果你想绝对确定明文和/或键永远不会在内存中暴露,那么你必须考虑使用硬件加密模块HSMS。不幸的是,这很昂贵。是的,但我做这件事和做其他事情一样多。可以在本机.NET代码中完成吗?很明显,MS正在考虑引入SecureString和所有现在接受它们的方法的问题。看起来他们在加密流中留下了一些洞。
unsafe public string Encrypt(SecureString textToEncrypt)
{
    using (SymmetricAlgorithm sa = GetAlgorithm())
    {
        ICryptoTransform ict = sa.CreateEncryptor();
        using (MemoryStream memStream = new MemoryStream())
        {
            using (CryptoStream cs = new CryptoStream(memStream, ict, CryptoStreamMode.Write))
            {
                IntPtr unmanagedBytes = Marshal.SecureStringToGlobalAllocAnsi(textToEncrypt);
                try
                {
                    byte* bytePointer = (byte*)unmanagedBytes.ToPointer();
                    byte[] singleByte = new byte[1];
                    while (*bytePointer != 0) // This is a null terminated value, so copy until we get a null
                    {
                        singleByte[0] = *bytePointer;
                        cs.Write(singleByte, 0, 1);
                        singleByte[0] = 0;
                        bytePointer++;
                    }
                }
                finally
                {
                    Marshal.ZeroFreeGlobalAllocAnsi(unmanagedBytes);
                }
            }
            string base64EncryptedText = Convert.ToBase64String(memStream.ToArray());
            return base64EncryptedText;
        }
    }
}