如何从SecureString正确发出二进制数据,以便以后可以将其转换为字符串?

时间:2017-12-01 15:58:16

标签: c# string encryption securestring

我需要从用户那里收集敏感信息字符串。我正在使用WPF PasswordBox来请求此信息。对于未经启动的人,PasswordBox控件提供SecurePassword属性,该属性是SecureString对象而不是不安全的string对象。在我的应用程序中,来自PasswordBox的数据将作为SecureString传递给加密方法。

我需要做的是将数据封送到基本上代表.Net string值的字节数组,而无需先将数据转换为.Net string。更具体地说,给定SecureString的值为......

  

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`〜!@#$%^& *()_- + = {[}] |:;“'<,>。?/ ≈母亲

...我怎样才能将它转换为一个字节数组,该数组相当于一个.Net字符串,该字符串已被序列化并写入带StreamWriter的流?

通过使用Marshal.SecureStringToCoTaskMemUnicode(...),我可以使用更传统的西方文本来完成此操作。但是,当我使用其他非典型字符和一串日文文本(请参阅最后几个粗体字符)创建上述文本字符串时,我获取分配给IntPtr位置的Unicode字节数组的方法不会似乎已经正常工作了。

如何以安全的方式发出SecureString的数据,使得返回的字节数据的结构与标准.Net字符串的字节数据相同,序列化为二进制输出?

注意

请暂时忽略所有安全问题。我正在为我的应用程序进行各种安全升级。现在,我需要使用SecureString来获取加密器的敏感数据。解密器(现在)仍然需要将此数据解密为string值,这就是为什么我需要将SecureString中的数据序列化为二进制格式,类似于二进制格式string对象。

我同意这种方法有点不幸,但是,我必须对现有应用程序进行渐进式改进,第一阶段是将SecureString对象中的数据从用户锁定到加密器

1 个答案:

答案 0 :(得分:1)

如果你需要编写安全字符串来流,我建议创建这样的方法:

public static class Extensions {
    public static void WriteSecure(this StreamWriter writer, SecureString sec) {
        int length = sec.Length;
        if (length == 0)
            return;
        IntPtr ptr = Marshal.SecureStringToBSTR(sec);
        try {
            // each char in that string is 2 bytes, not one (it's UTF-16 string)
            for (int i = 0; i < length * 2; i += 2) {
                // so use ReadInt16 and convert resulting "short" to char
                var ch = Convert.ToChar(Marshal.ReadInt16(ptr + i));
                // write
                writer.Write(ch);
            }
        }
        finally {
            // don't forget to zero memory
            Marshal.ZeroFreeBSTR(ptr);
        }
    }
}

如果你真的需要字节数组 - 你也可以重用这个方法:

byte[] result;
using (var ms = new MemoryStream()) {
    using (var writer = new StreamWriter(ms)) {
        writer.WriteSecure(secureString);
    }
    result = ms.ToArray();
}

虽然来自第一条评论的方法可能会更加一致(不确定这对你来说是否重要)。