Secure Strings in .NET – Part I

Hi Gaurav Sharma here.......

I am a developer on the CISG India team based in Hyderabad and I joined Microsoft four months ago. I love playing computer games and recently finished Call of duty 4. For the last three years I've been working with .NET and have worked on different kinds of applications that include ERP solutions, utilities and web portals. Apart from computer games I like watching soccer; there was a time (long back) when I used to watch each and every match of English premier league. I've a blog that I last updated when I joined MS. This looks like enough information about me, let us start with our secure string story.

A few months back I was looking into improvements that Microsoft made to it's .NET base class library since its inception and I stumbled upon a class named Secure String. I found that exiting and made a small blog entry related to this new class.

In this write up I'll try to focus on the need for secure string class as well as its internal working and usage. I'll also try to do a feature comparison between String and SecureString class. You will find code examples and IL code with theoretical explanations. There are a few tools that I will use for creating code and IL samples. These are:

  • Visual Studio 2008
    I'll use Visual studio for creating code samples. If you do not have Visual studio installed on your system you can download and install the free express version of our beloved IDE.
  • .NET class viewer
    I will use .NET Reflector but you can use any tool of your choice.
    Another great tool and will be used to look at IL code, manifest information and assembly metadata
  • Memory Profiler
    I'll try to use this tool to show how object creation of string class differs from secure string

The structure of this two part write up (this is part one) is as follows;

  1. Part I
    • Introduction
    • SecureString Class
    • Members
    • Usage
  2. Part 2
    • Internals
    • SecureString vs. String class
      • Performance
      • Usability
    • Misc.

Let's start our journey to explore SecureString,


Since the inception of .NET programming, I doubt whether there is any other class used more frequently than the String class. We can use string to represent any textual and literal data like name, location, occupation etc. There are four ways in which we can represent individual character and their collections:

  1. System.Char
  2. System.String
  3. System.Text.StringBuilder, and
  4. System.Security.SecureString

System.String is an ordered set of characters that is immutable. String is a reference type so every string object that we create lives on the heap rather than on the thread stack. Because strings are immutable, once they are created we can not change them. We can not add or remove or manipulate existing string objects. Whenever we try to manipulate string objects we discard old objects (they are still there on heap) and create new ones. Let's see a code snippet,

   1:  using System;
   3:  namespace Gaurav.Samples.SecureString
   4:  {
   5:      class Program
   6:      {
   7:          static void Main(string[] args)
   8:          {
   9:              string name = "Gaurav";
  10:              name = name + "Sharma";
  11:              name = name + "Mr.";
  12:              Console.WriteLine(name);
  13:              Console.Read();
  14:          }
  15:      }
  16:  }

This will create three string objects. When we add "Sharma" to the already existing string name, a new string object is created and the name variable now refers to this new object. The old string object is marked for garbage collection. Same thing happens again when we try to append "Mr." to name. A new object is created and we have two old objects marked for garbage collection. The next garbage collection run will clear out these two objects.

Now suppose you have a application that stores username, password and credit card number in string objects. These string objects are basically in memory character arrays and if there is any unsafe or unmanaged code is allowed to execute, that code can snoop around the process's address space, locate the string with sensitive data and can use this data in a bad way.

Strings are not pinned objects. Pinned objects are those whose memory can not be compacted by garbage collection. As strings are not pinned objects, our garbage collector is  free to move strings in memory. When string objects are moved several garbage copies of string data are created whose memory will be reclaimed by the garbage collector during later runs. Having so many copies of data (especially if sensitive) can create issues.

String keeps a plain text copy i.e. not encrypted, so our data is under continuous danger of being read by some one who can read our process's memory. If our string object is used for a small time span and then garbage collected, it's possible that the common language runtime (CLR) will not reuse the object's memory immediately (this depends on the generation of the object). This can be a potentially compromising situation with our strings data left in memory. Moreover as strings are immutable you can not overwrite them with blank data, the code below for example will not clear out any data.

   1:  using System;
   3:  namespace Gaurav.Samples.SecureString
   4:  {
   5:      class Program
   6:      {
   7:          static void Main(string[] args)
   8:          {
   9:              string name = "Gaurav";
  10:              //this will create new object and will not clear out old object's data
  11:              name = "";
  12:              Console.WriteLine(name);
  13:              Console.Read();
  14:          }
  15:      }
  16:  }

If at any time you run out of memory, string memory contents can get into SWAP files, where they can be a lot easier to access by the bad guys (hackers). Due to these issues Microsoft introduced added another secure string class in FCL,

  1. Class Name: SecureString
  2. Namespace: System.Security
  3. Assembly: mscorlib.dll


Some facts about secure string class are:

  1. When a new object of secure string class is constructed, the CLR allocates a block of "unmanaged" memory that contains an array of characters. The garbage collector is not aware of this memory block because this is unmanaged.
  2. Data is encrypted using Data Protection API or DPAPI.
  3. Methods available in Secure String class like AppendChar, InsertAt...first decrypts the data then performs the action and then again re-encrypts the data.
  4. This class implements the IDisposable interface which means that you can clean out your object deterministically. Dispose method zeroes out the content of the memory buffer.
  5. This class is also derived from CriticalFinalizerObject. This guarantees that object's finalizer method is called , which means characters will be zeroed out and memory will be freed. 
  6. Unlike string, objects are mutable. This means that if we pass this object to different functions, only one copy of object will be there.
  7. This is non CLS compliant (use of pointers).
  8. This is a sealed class (like all data types).


MSDN provides a good information about members of  the SecureString class. page will give you enough information that will equip you for SecureString usage. For your convenience I'll add member summary here, but for latest information you should always check MSDN.



There are not many examples that uses SecureString class so I'll try to show you where this class is used in the framework class library by developing a small application that uses secure string. To avoid complications our sample application will be a small (micro) console application that stores passwords in secure string and renders it to console. Let's start with knowing about FCL usage of SecureString class,

  1. Framework Class Library usage
    • System.Diagnostics
      • System.Diagnostics.Eventing.Reader.EventLogSession..ctor(String, String, String, SecureString, SessionAuthentication) [.ctor=constructor in IL]
      • System.Diagnostics.Process.Start(String, String, SecureString, String) : Process
      • System.Diagnostics.Process.Start(String, String, String, SecureString, String) : Process
      • System.Diagnostics.ProcessStartInfo.Password : SecureString
    • System.Runtime.InteropServices
      • System.Runtime.InteropServices.Marshal.SecureStringToBSTR(SecureString) : IntPtr
      • System.Runtime.InteropServices.Marshal.SecureStringToCoTaskMemAnsi(SecureString) : IntPtr
      • System.Runtime.InteropServices.Marshal.SecureStringToCoTaskMemUnicode(SecureString) : IntPtr
      • System.Runtime.InteropServices.Marshal.SecureStringToGlobalAllocAnsi(SecureString) : IntPtr
      • System.Runtime.InteropServices.Marshal.SecureStringToGlobalAllocUnicode(SecureString) : IntPtr
    • System.Security.Cryptography
      • System.Security.Cryptography.CspParameters..ctor(Int32, String, String, CryptoKeySecurity, SecureString) [CSP = Crypto Service Providers]
      • System.Security.Cryptography.CspParameters.KeyPassword : SecureString
      • System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[], SecureString)
      • System.Security.Cryptography.X509Certificates.X509Certificate..ctor(Byte[], SecureString, X509KeyStorageFlags)
      • System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String, SecureString)
      • System.Security.Cryptography.X509Certificates.X509Certificate..ctor(String, SecureString, X509KeyStorageFlags)
      • System.Security.Cryptography.X509Certificates.X509Certificate.Export(X509ContentType, SecureString) : Byte[]
      • System.Security.Cryptography.X509Certificates.X509Certificate.Import(Byte[], SecureString, X509KeyStorageFlags) : Void
      • System.Security.Cryptography.X509Certificates.X509Certificate.Import(String, SecureString, X509KeyStorageFlags) : Void
      • System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[], SecureString)
      • System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[], SecureString, X509KeyStorageFlags)
      • System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String, SecureString)
      • System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(String, SecureString, X509KeyStorageFlags)
      • System.Security.Cryptography.X509Certificates.X509Certificate2.Import(Byte[], SecureString, X509KeyStorageFlags) : Void
      • System.Security.Cryptography.X509Certificates.X509Certificate2.Import(String, SecureString, X509KeyStorageFlags) : Void
    • System.Windows.Controls
      • System.Windows.Controls.PasswordBox.SecurePassword : SecureString
      • System.Windows.Controls.PasswordBox.SetSecurePassword(SecureString) : Void
      • System.Windows.Controls.PasswordTextContainer..ctor(PasswordBox)
      • System.Windows.Controls.PasswordTextContainer.SetPassword(SecureString) : Void

Below I've added what's probably the most exhaustive list of SecureString usage you will ever find on web. Some of these uses secure string internally and some of them are not public. You will find a list of places where SecureString is used, places where SecureString objects are exposed, where SecureString objects are initialised and assemblies on which SecureString depends.



Now let's move to our sample application.

  1. Sample application
    • Create a C# console application. You can name it as you like. Our application is very simple. It takes a password string from user and renders it back to the console.
    • Our sample application will have two methods, one Main [entry point] and other to render secure string on standard output stream [console in our case]
    • Make sure you check unsafe usage from project build properties window. This will add '/unsafe' switch during compilation. '/unsafe' compilation switch is required to compile any unsafe code. Important thing is that we don't need '/unsafe' switch to create secure string objects, this check is required to access secure string's unmanaged memory location using pointers. If you use CSC.EXE [C # compiler] from console you can use '/unsafe' switch to compile unsafe code.


    • Our class looks like this

         1:  using System;
         2:  using System.Security; //required for SecureString
         3:  using System.Runtime.InteropServices; //required for SecureString
         5:  namespace Gaurav.SecureStringSamples.ConsoleLoginSample
         6:  {
         7:      class Program
         8:      {
         9:          static void Main(string[] args)
        10:          {
        11:              using (SecureString password = new SecureString())
        12:              {
        13:                  ConsoleKeyInfo consoleKeyInfo; //used to read console keys
        14:                  Console.Write("Please enter password: ");
        15:                  while (true)
        16:                  {
        17:                      consoleKeyInfo = Console.ReadKey(true);
        18:                      if (consoleKeyInfo.Key == ConsoleKey.Enter) break;
        19:                      password.AppendChar(consoleKeyInfo.KeyChar);
        20:                      Console.WriteLine("*");
        21:                  }
        22:                  Console.WriteLine();
        23:                  RenderSecureString(password);
        24:                  Console.Read();
        25:              }
        26:              Console.WriteLine("done");
        27:              Console.Read();
        28:          }
        29:          private unsafe static void RenderSecureString(SecureString toBeDisplayedSecureStr)
        30:          {
        31:              Char* charPtr = null;
        32:              try
        33:              {
        34:                  //cast int ptr to char ptr
        35:                  //copy content from secure string to block of unmanaged memory
        36:                  charPtr = (Char*)Marshal.SecureStringToCoTaskMemUnicode(toBeDisplayedSecureStr);
        37:                  for (Int32 count = 0; count < toBeDisplayedSecureStr.Length; count++) Console.Write(charPtr[count]);
        38:              }
        39:              finally
        40:              {
        41:                  //frees unmanaged string pointer allocated by Marshal.SecureStringToCoTaskMemUnicode
        42:                  if (charPtr != null) Marshal.ZeroFreeCoTaskMemUnicode((IntPtr)charPtr);
        43:              }
        44:          }
        45:      }
        46:  }

    • Output window will look something like this


Cool, we have now created our very first secure string example. Next time I'll add some performance tests to this example and compare them with the standard string class.

Stay tuned!

Comments (7)
  1. Anonymous says:

    I see you used secure strings with a console application, but how do we use them with WPF and Windows Forms.

    I never found a good way to bind them to a text box. In order to bind a text box to them you have to convert them to a string. Once you convert them to a string it is now no better then leaving them in a string.

    I do not really want to create my own textbox that binds to a secure string, but without one, it seems rather pointless.

    Maybe I am just missing something here.

  2. Anonymous says:

    Varun in our team has posted part I of series about SecureString in .NET. Awesome blog entry talks about

  3. Anonymous says:

    Nice Writeup dude. Keep it up. Best Luck and Cheerio !!!

  4. Anonymous says:

    The problem I see is when you enter handle the data before and after you use the secure string. Won’t it be up to the garbage collector to clean it up?

  5. Anonymous says:

    Nice article but you’re not entirely correct on strings being stored on the heap and being garbage-collected. Strings are stored inside the string pool (precisely because they are used so often):

  6. cisg says:

    Hi Ronald, Guarav here….

    • Strings

    o String type is immediately derived from Object, making it  reference type, and therefore, String objects always live in the heap, never on a thread’s stack.

    • String Interning

    o This is a feature provided by CLR. When, the Common Language Runtime initializes, it created an internal data structure (hash table) in which keys are strings and the values are references to String objects in the managed heap. Initially this data structure is empty.

    o The String class offers two methods that allow you to access this internal hash table:

     public static String Intern(String str) – Intern a particular string

     public static String IsInterned(String str) – Checks weather a string is interned or not

    o By default, when an assembly is loaded, the CLR interns all of the literal strings described in the assembly’s metadata. Note that the garbage collector can’t free the strings that the internal hash table refers to because the hash table holds the reference to those String objects. String objects referred to by the internal hash table can’t be freed until the App Domain is unloaded or the process terminates.

    o Microsoft learned that this hurts performance significantly due to the additional hash table lookups, so it is now possible to turn this "feature" off. If an assembly is marked with a System.Runtime.CompilerServices.CompilationRelaxationsAttribute specifying the System.Runtime.CompilerServices.CompilationRelaxations.NoString-Interning flag value, the CLR may, according to the ECMA specification, choose not to intern all of the strings defined in that assembly’s metadata.

    o Note that, in an attempt to improve your application’s performance, the C# compiler always specifies this attribute/flag whenever you compile an assembly. Even if an assembly has this attribute/flag specified, the CLR may chose to intern the strings, but you should not count on this.

    • String Pooling

    o When compiling source code, your compiler must process each literal string and emit the string into the managed module’s metadata. If the same literal string appears several times in your source code, emitting all of these strings into the metadata will bloat the size of the resulting file.

    o To remove this bloat, many compilers (include the C# compiler) write the literal string into the module’s metadata only once. All code that references the string will be modified to refer to the one string in the metadata. This process is nothing new—C/C++ compilers have been doing it for years. This is purely for literal strings that we define in our code.

    You can get more information on this from Jeffrey Richter’s great book, CLR via C#.

Comments are closed.

Skip to main content