160

如何转换StringSecureString

4

14 回答 14

218

还有另一种在SecureString和之间转换的方法String

1. 字符串到 SecureString

SecureString theSecureString = new NetworkCredential("", "myPass").SecurePassword;

2. SecureString 到 String

string theString = new NetworkCredential("", theSecureString).Password;

这是链接

于 2017-03-29T04:51:18.190 回答
158

你没有。使用 SecureString 对象的全部原因是避免创建字符串对象(该对象被加载到内存中并以纯文本形式保存在那里,直到垃圾回收)。但是,您可以通过附加字符将字符添加到 SecureString。

var s = new SecureString();
s.AppendChar('d');
s.AppendChar('u');
s.AppendChar('m');
s.AppendChar('b');
s.AppendChar('p');
s.AppendChar('a');
s.AppendChar('s');
s.AppendChar('s');
s.AppendChar('w');
s.AppendChar('d');
于 2009-10-15T05:28:23.663 回答
70

下面的方法有助于将字符串转换为安全字符串

private SecureString ConvertToSecureString(string password)
{
    if (password == null)
        throw new ArgumentNullException("password");

    var securePassword = new SecureString();

    foreach (char c in password)
        securePassword.AppendChar(c);

    securePassword.MakeReadOnly();
    return securePassword;
}
于 2014-06-02T14:44:37.293 回答
24

你可以按照这个:

string password = "test";
SecureString sec_pass = new SecureString();
Array.ForEach(password.ToArray(), sec_pass.AppendChar);
sec_pass.MakeReadOnly();
于 2014-08-06T04:38:05.130 回答
14

这是一个便宜的 linq 技巧。

            SecureString sec = new SecureString();
            string pwd = "abc123"; /* Not Secure! */
            pwd.ToCharArray().ToList().ForEach(sec.AppendChar);
            /* and now : seal the deal */
            sec.MakeReadOnly();
于 2015-06-25T20:48:24.590 回答
9

我会把这个扔出去。为什么?

您不能只是将所有字符串更改为安全字符串,然后您的应用程序突然就“安全”了。安全字符串旨在尽可能长时间地保持字符串加密,并且仅在很短的时间内解密,在对其执行操作后擦除内存。

我会冒昧地说,在担心保护应用程序字符串之前,您可能需要处理一些设计级别的问题。向我们提供有关您尝试做什么的更多信息,我们可能会提供更好的帮助。

于 2009-10-15T05:25:28.773 回答
8
unsafe 
{
    fixed(char* psz = password)
        return new SecureString(psz, password.Length);
}
于 2015-03-03T18:20:41.480 回答
8

我只是想向所有说“这不是重点SecureString”的人指出,许多提出这个问题的人可能在一个应用程序中,无论出于何种原因,无论是否合理,他们并不特别担心拥有密码的临时副本作为可 GC 的字符串放在堆上,但他们必须使用接受SecureString对象的 API。所以,你有一个你不关心的应用程序密码是否在堆上,也许它仅供内部使用并且密码仅存在,因为它是底层网络协议所要求的,并且您发现存储密码的字符串不能用于例如设置远程 PowerShell运行空间——但没有简单、直接的单行代码来创建SecureString您需要的内容。这是一个小小的不便——但可能值得确保真正需要的应用程序不会SecureString诱使作者使用System.StringSystem.Char[]中介。:-)

于 2018-04-16T15:45:14.677 回答
6

没有花哨的 linq,没有手动添加所有字符,简单明了:

var str = "foo";
var sc = new SecureString();
foreach(char c in str) sc.appendChar(c);
于 2016-07-12T10:31:30.037 回答
4

我同意 Spence (+1),但如果您这样做是为了学习或测试 pourposes,您可以在字符串中使用 foreach,使用 AppendChar 方法将每个字符附加到安全字符串。

于 2009-10-15T05:29:34.637 回答
4

以下 2 个扩展应该可以解决问题:

  1. 对于一个char数组

    public static SecureString ToSecureString(this char[] _self)
    {
        SecureString knox = new SecureString();
        foreach (char c in _self)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
    
  2. 而对于string

    public static SecureString ToSecureString(this string _self)
    {
        SecureString knox = new SecureString();
        char[] chars = _self.ToCharArray();
        foreach (char c in chars)
        {
            knox.AppendChar(c);
        }
        return knox;
    }
    

感谢John DaggAppendChar推荐。

于 2017-07-04T14:05:35.173 回答
3

如果您想将 astring到 a的转换压缩SecureStringLINQ语句,可以如下表示:

var plain  = "The quick brown fox jumps over the lazy dog";
var secure = plain
             .ToCharArray()
             .Aggregate( new SecureString()
                       , (s, c) => { s.AppendChar(c); return s; }
                       , (s)    => { s.MakeReadOnly(); return s; }
                       );

但是,请记住,使用LINQ不会提高此解决方案的安全性。它与从string到的任何转换存在相同的缺陷SecureString。只要原始string数据保留在内存中,数据就很容易受到攻击。

话虽这么说,上面的语句可以提供的是保持 的创建SecureString,它的初始化与数据并最终锁定它以防止修改。

于 2015-07-28T08:05:50.633 回答
0

为了完整起见,我添加了两个单元测试和方法来从 char 数组和字符串转换为 SecureString 并再次转换回来。您应该尝试完全避免使用字符串,并且只传递指向 char 数组的指针或 char 数组本身,就像我在此处提供的方法一样,因为字符串是不安全的,因为它们将数据以纯文本形式保存在托管内存中,数量相当不确定在下一次 GC 运行或强制运行之前的时间,最好尽快将您的字符数组放入 SecureString 并将其保留在那里并再次将其作为字符数组读回。

测试如下所示:

using NUnit.Framework;
using System;
using SecureStringExtensions;
using System.Security;

namespace SecureStringExtensions.Test
{
    [TestFixture]
    public class SecureStringExtensionsTest
    {
        [Test]
        [TestCase(new char[] { 'G', 'O', 'A', 'T', '1', '2', '3' })]
        public void CopyCharArrayToSecureStringAndCopyBackToCharArrayReturnsExpected(char[] inputChars)
        {
            SecureString sec = inputChars.ToSecureString();
            var copiedFromSec = sec.FromSecureStringToCharArray();
            CollectionAssert.AreEqual(copiedFromSec, inputChars);                
        }

        [Test]
        [TestCase("GOAT456")]
        public void CopyStringToSecureStringAndCopyBackToUnsafeStringReturnsExpected(string inputString)
        {
            SecureString sec = inputString.ToSecureString();
            var copiedFromSec = sec.FromSecureStringToUnsafeString();
            Assert.AreEqual(copiedFromSec, inputString);
        }
    }
}

我们在这里有我们的扩展方法:

using System;
using System.Runtime.InteropServices;
using System.Security;

namespace SecureStringExtensions
{
    public static class SecureStringExtensions
    {
        public static SecureString ToSecureString(this string str)
        {
            return ToSecureString(str.ToCharArray());
        }

        public static SecureString ToSecureString(this char[] str)
        {
            var secureString = new SecureString();
            Array.ForEach(str, secureString.AppendChar);
            return secureString;
        }

        /// <summary>
        /// Creates a managed character array from the secure string using methods in System.Runetime.InteropServices
        /// copying data into a BSTR (unmanaged binary string) and then into a managed character array which is returned from this method.
        /// Data in the unmanaged memory temporarily used are freed up before the method returns.
        /// </summary>
        /// <param name="secureString"></param>
        /// <returns></returns>
        public static char[] FromSecureStringToCharArray(this SecureString secureString)
        {
            char[] bytes;
            var ptr = IntPtr.Zero;
            try
            {
                //alloc unmanaged binary string  (BSTR) and copy contents of SecureString into this BSTR
                ptr = Marshal.SecureStringToBSTR(secureString);
                bytes = new char[secureString.Length];
                //copy to managed memory char array from unmanaged memory 
                Marshal.Copy(ptr, bytes, 0, secureString.Length);
            }
            finally
            {
                if (ptr != IntPtr.Zero)
                {
                    //free unmanaged memory
                    Marshal.ZeroFreeBSTR(ptr);
                }
            }
            return bytes;
        }

        /// <summary>
        /// Returns an unsafe string in managed memory from SecureString. 
        /// The use of this method is not recommended - use instead the <see cref="FromSecureStringToCharArray(SecureString)"/> method
        /// as that method has not got multiple copies of data in managed memory like this method.
        /// Data in unmanaged memory temporarily used are freed up before the method returns.
        /// </summary>
        /// <param name="secureString"></param>
        /// <returns></returns>
        public static string FromSecureStringToUnsafeString(this SecureString secureString)
        {
            if (secureString == null)
            {
                throw new ArgumentNullException(nameof(secureString));
            }
            var unmanagedString = IntPtr.Zero;
            try
            {
                //copy secure string into unmanaged memory
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(secureString);
                //alloc managed string and copy contents of unmanaged string data into it
                return Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                    if (unmanagedString != IntPtr.Zero)
                {
                    Marshal.FreeBSTR(unmanagedString);
                }
            }
        }

    }
}

在这里,我们使用 System.Runtime.InteropServices 中的方法临时分配 BSTR(二进制非托管字符串),并确保释放临时使用的非托管内存。

于 2021-07-21T22:11:10.020 回答
-1

你可以使用这个简单的脚本

private SecureString SecureStringConverter(string pass)
{
    SecureString ret = new SecureString();

    foreach (char chr in pass.ToCharArray())
        ret.AppendChar(chr);

    return ret;
}
于 2017-10-28T06:32:43.107 回答