Storing data in a SecureString has one big advantage – if you try to use the same files on another PC or account, Windows will reject them and you will have to sign in again. And nobody can get to the password either, unless you happen to display it somewhere in the application, worst of all in plain text. Since I kept thinking the bug was somewhere in the classes that work with SecureString, I looked for other ways to work with it. In the end I created these 2 classes – the Unsafe class, as its name suggests, may not look trustworthy to users, because such an assembly must be marked as unsafe, otherwise the compiler will not compile it. That is why I recommend using the SecureStringHelper class, which does exactly the same job, just in the context of managed code. Now on to both classes:
Unsafe:
using System;
using System.Runtime.InteropServices;
using System.Security;
public static class Unsafe
{
public static SecureString ToSecureString(this string value)
{
unsafe
{
fixed (char* valuePointer = value)
{
SecureString secureString = new System.Security.SecureString(valuePointer, value.Length);
secureString.MakeReadOnly();
return secureString;
}
}
}
public static string ToInsecureString(SecureString securePassword)
{
IntPtr unmanagedString = IntPtr.Zero;
try
{
unmanagedString = Marshal.SecureStringToGlobalAllocUnicode(securePassword);
return Marshal.PtrToStringUni(unmanagedString);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
}
}
}SecureStringHelper:
using System;
using System.Security;
public class SecureStringHelper
{
public static SecureString ToSecureString(string input)
{
SecureString secure = new SecureString();
foreach (char c in input)
{
secure.AppendChar(c);
}
secure.MakeReadOnly();
return secure;
}
public static string ToInsecureString(SecureString input)
{
string returnValue = string.Empty;
IntPtr stringPointer = System.Runtime.InteropServices.Marshal.SecureStringToBSTR(input);
try
{
returnValue = System.Runtime.InteropServices.Marshal.PtrToStringBSTR(stringPointer);
}
finally
{
System.Runtime.InteropServices.Marshal.ZeroFreeBSTR(stringPointer);
}
return returnValue;
}
}