C# MemoryStream到SecureString:擦除内存

C# MemoryStream到SecureString:擦除内存,c#,C#,我正在从内存流中检索一个未加密的密钥,将其转换为某种字符串,并将该字符串与.Net的加密函数一起使用以加密数据。我需要确保未加密的键在使用后从内存中擦除。我找到了SecureString,我认为它可以处理字符串,但我不确定如何在密钥变成SecureString之前擦除其内存 因此,一切工作的方式是: MemoryStream->char[]->SecureString SecureString被传递到字符数组的指针,所以它在完成时会擦除字符数组?这是它的构造函数: SecureString(Ch

我正在从
内存流
中检索一个
未加密的
密钥,将其转换为某种字符串,并将该字符串与.Net的
加密
函数一起使用以加密数据。我需要确保
未加密的
键在使用后从内存中擦除。我找到了
SecureString
,我认为它可以处理字符串,但我不确定如何在密钥变成
SecureString
之前擦除其内存

因此,一切工作的方式是:

MemoryStream->char[]->SecureString

SecureString
被传递到字符数组的指针,所以它在完成时会擦除字符数组?这是它的构造函数:

SecureString(Char*,int32)
有一个实现它的示例

但是,一旦
SecureString
擦除数据(如果它擦除数据),我仍然需要知道如何擦除
MemoryStream
中的数据,以及为了获得
char[]
而必须创建的任何中间对象

所以这个问题可以归结为两个部分:

如何将
MemoryStream
直接读入
char[]
而不在内存中生成任何其他内容?(如果不可能,理想的转换是什么?即,
MemoryStream->string->char[]
?)

以及


完成后,如何覆盖
MemoryStream
(以及在
MemStream->char[]
过程中创建的任何其他签名)所使用的内存?

首先,
SecureString
不会擦除输入
char*
的内存-您对此负责。它只会清理自己的内部存储

要将
MemoryStream
的内容读取/清除为本地
char[]
,只需分配数组(假设流包含有效字符串):


当然,这一切都假定
不安全
代码。但是,没有完全保证的方法可以从内存中清除所有可能的密钥实例-在调用将密钥放入流的过程中,它可能会被复制多次(在您无法访问的各种私有缓冲区中)因此,你可能甚至不知道有多少份拷贝在你身边徘徊。

你所尝试的问题比你想象的更大。MemoryStream很可能被其他东西使用,并且很可能随着时间的推移而增大

每次数据增长时,都会在内部将其复制到一个新数组中,并释放旧数组=>您的密钥可能会在此处泄漏

此外,MemoryStream最有可能被其他API使用。其他API很可能不会安全地删除密钥,因为它们不是设计用来删除密钥的


但要回答您最初的问题:如果密钥只是ascii字符,您可以将字节复制到字符数组中,然后用随机垃圾覆盖原始字节。您可以使用
GetBuffer

直接访问其内容,而不在内存中生成任何其他内容是什么意思?当您读取流时,您的密钥已经在内存中——可能是未加密的。您可以将其读入本地
char[]
并传递到
SecureString
。完成后覆盖并删除阵列。这不是你要找的吗?[编辑问题解释]是的,我也这么想。我试图避免手动覆盖内存中的任何内容(因为我不知道怎么做)。因此,如果我有内存流,将其读入一个char[],使用安全字符串(它会擦除char数组,对吗?),那么我需要从memoryStream中擦除内存…对吗?我该怎么做?还有其他的创造吗?简单的回答是你不能。一旦你将数据保存在一个常规的托管字符串中,你就已经丢失了,而且没有真正可靠的方法来消除它。那么单独的appdomain呢?@bordeo这里的要点是,你不应该将不希望执行程序的用户能够访问的信息存储在内存中。如果您不希望运行代码的计算机管理员访问未加密的敏感数据,请不要将其保留在内存中。如果您想做一些敏感的事情,并且您想确保您的用户永远无法访问您正在使用的数据,那么您需要向您拥有的服务器/计算机发出请求,在那里完成工作,然后将结果发送回给他们。您应该使用MemorySteams GetBuffer而不是Array。它避免了创建内存内部缓冲区的副本StreamToArray将创建额外的副本,GetBuffer不会。另外,如果长度不是偶数,则截断最后一个字节。@Zotta
length
必须是偶数,如果流包含有效的UTF-16字符串。OP必须完成他/她的错误检查作业。:)
// Get the contents of the stream.
var byKey = oMS.GetBuffer ();

fixed ( byte *pBytes = byKey )
{
    var oSecStr = new SecureString ( (char*) pBytes, 
        (int) ( oMS.Length / 2 ) );

    // Clear stream (there's no separate char/byte array
    // to clean).
    Array.Clear ( byKey, 0, byKey.Length );
}