Convert String to SecureString

Viewed 227559

How to convert String to SecureString?

14 Answers

For completeness, I added two unit tests and methods to convert from char array and string into SecureString and back again. You should try to avoid strings altogether and only pass in either a pointer to a char array or the char array itself as in the methods I provide here, as strings are unsafe since they keep data in plain text in managed memory for rather indeterministic amount of time until next GC is run or forced, it is better to put your character array as soon as possible into a SecureString and keep it there and read it back again as a character array also.

The tests look like this:

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);
        }
    }
}

And we have our extension methods here:

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);
                }
            }
        }

    }
}

Here, we use methods from System.Runtime.InteropServices to alloc BSTR (binary unmanaged string) temporarily and also make sure to free up temporary used unmanaged memory.

you can use this simple script

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

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

    return ret;
}
Related