Secure Strings

A lot of programs use some form of passwords. These are usually kept in memory. The issue here is that a program's used memory is very easy to read out and your unsecured password will be there in plain sight.

For this specific reason, the SecureString (System.Security) class is available, which will keep your string encrypted in memory.

Since this class does not have an apparent constructor that receives a string, people tend to create an empty SecureString, iterate their string and call AppendChar for each and every iteration. Not only is this a tedious process, the .NET framework will have to unprotect the value each time and protect it again after adding the char. The good news, though, is that this entire process is done in unmanaged memory.

This whole process, however, can be done in a much easier way, by using unsafe code (tick the option to enable it in your project settings). This will enable you to create a char pointer (char*) to your string and pass it to the SecureString constructor as follows:

    unsafe static class UnsafeExtensions
    {
        public static SecureString ToSecureString(this string password)
        {
            fixed (char* passwordChars = password)
            {
                var securePassword = new SecureString(passwordChars, password.Length);
                securePassword.MakeReadOnly();

                return securePassword;
            }
        }
    }

Don't forget to mark it as read-only when you're done to prevent it from being modified.

Getting your string back, is just as easy and can be done by calling SecureStringToGlobalAllocUnicode:

    unsafe static class UnsafeExtensions
    {
        public static string ToUnsecureString(this SecureString securePassword)
        {
            IntPtr unmanagedString = IntPtr.Zero;
            try
            {
                unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
                return Marshal.PtrToStringUni(unmanagedString);
            }
            finally
            {
                Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
            }
        }
    }

One could, however, argue that you don't have control over how long that string will remain in your memory. Instead of working with a string, we could work with a byte array instead. This will be easy to clear from memory afterwards.

We could go a step further and automate the process as follows:

    unsafe static class UnsafeExtensions
    {
        [DllImport("msvcrt.dll", EntryPoint = "memcpy", CallingConvention = CallingConvention.Cdecl, SetLastError = false)]
        static extern IntPtr memcpy(void* dest, void* src, int count);

        public static T Process<T>(this SecureString input, Func<byte[], T> process)
        {
          var ptr = IntPtr.Zero;
          byte[] bytes = null;

          try
          {
              ptr = Marshal.SecureStringToBSTR(input);

              bytes = new byte[input.Length * sizeof(char)];
              fixed (void* b = bytes)
                  memcpy(b, ptr.ToPointer(), bytes.Length);

              return process(bytes);
          }
          finally
          {
              if (bytes != null)
                  bytes.Clear();

              if (ptr != IntPtr.Zero) Marshal.ZeroFreeBSTR(ptr);
          }
    }

Steven Thuriot

Developer, tinkerer, lifetime student, full time nerd and somewhat of an otaku. Graduated applied computer science. Likes to complain about traffic.

Belgium