How is SecureString "encrypted" and still usable?

11,583

Solution 1

I'm quoting from an article about the DPAPI which is used to derive the key. This should answer most questions that you have about SecureString.

And yes, SecureString has drawbacks and is not completely secure, there are ways to access to data, for example, injecting Hawkeye into the process is mentioned on MSDN as a way to extract the SecureString. I have not personally verifed this assertation.

DAPI Key Management

DAPI is a symmetric based encryption technique, which means it uses the same key to both encrypt and decrypt data. Before getting to some examples of how to use DAPI it's worth covering how DAPI manages its key. For the most part DAPI key management process is invisble and you generally don't need to worry about it, which is the main reason why DAPI is a good approach.

In the introduction I wrote that the master key is generated from the user's login password. This isn't the complete picture. What actually happens is Windows uses the user's login password to generate a master key. This master key is protected using the user's password and then stored along with the user's profile. This master key then gets used to derive a number of other keys and it's these other keys that are used to protect the data.

The reason why Windows does this is it allows applications to add additional information, called entropy, to the process of generating the individul keys. You see if every application running under the user's login account used the same key then every application could unprotect DAPI protected data. Sometimes you might want applications to be able to share DAPI protected data; however, sometimes you won't. By letting the application contribute entropy to the generation of a key then that key becomes application specific and any data that is protected by that application can only be unprotected again if they know the entropy.

Although generating a master key, and then using that master key to generate other keys to do the actual encryption, might seem like a long winded approach it does have one major advantage. Since there is an additional level of abstraction between the user password protected master key and the actual keys used to protect the data it means that when the user changes their password then only the master key need to be re-protected; none of the protected data needs to be re-protected. Since the master key is much smaller in size than the data then a significant performance saving is made.

When the user's password changes then of course a new master key is generated. This new master key is then used to generate new individual keys. However, since all the previously generated individual keys were derived from the old master key then Windows needs to store all previous master keys, which it does. Windows never forgets a master key and all protected data is marked with a GUID that indicates which master key was used to protect the data. So in terms of adaptability DAPI is able to cope with changes to users' passwords, while ensuring a) that protected data doesn't need to be re-protected, and b) that keys used to previously protect data as still available, and c) it does all this automatically for you.

Unless the computer is a member of a domain DAPI can only unprotected data on the same machine that was used to protect it.

As well as allowing user level protection, in that master keys are based on user passwords and protected data for one user cannot be unprotected by another user, DAPI also provides machine level protection, in that the master keys are based on machine specific information. Machine level master keys allow applications to store protected data so that it can be unprotected by all users of the application. The only difference in the process already described is the master key is generated from machine specific information not user specific information.

Solution 2

I looked at one point into the code for it and it uses Windows's advapi32 to do its dirty work. So the key isn't stored in the application's memory.

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static int SystemFunction040([In, Out] SafeBSTRHandle pDataIn, [In] uint cbDataIn, [In] uint dwFlag)

Which is better known as RtlEncryptMemory.

It decrypts with RtlDecryptMemory (SystemFunction041).

I'm sure the compiler does something with the SecurityCriticalAttribute as well.

edit this was reflected using 4.0. other versions might different.

Solution 3

As others have already answered, the contents of SecureString are encrypted using DPAPI, so the keys aren't stored in your application, they're part of the OS. I'm not 100% positive, but I would assume that SecureString uses a user-specific key, so that even if another process gains access to the block of memory, it would have to be running under the same credentials in order to simply decrypt the content using the DPAPI. Even if not, the machine key (in theory) prevents the string from being readily decrypted if transferred to another system.

More important with SecureString is how & when you use it. It should be used to store string data that needs to be retained in memory for "extended" periods of time, but which are not frequently needed in their decrypted form. At some point, you're going to have to decrypt it into a regular old System.String, or a System.Char[]. This is when it's most vulnerable in memory. If you do this too often, then you have multiple copies of the decrypted string floating around in memory waiting to be collected.

As a general rule, if I'm reading encrypted data (say login credentials) that I need to retain for infrequent use (PayPal or Amazon API interaction, for instance), then I store/cache those credentials as SecureString, then decrypt it as-needed only long enough to make the web service calls, and ensure that the lifespan of any decrypted copy is only a few lines of code.

It's probably also wise to use critical blocks or similar to hint to the CLR that it should not context-switch while the decrypted string is in use, to improve the chances that any decrypted copies are collected before the memory is cached or swapped.

Solution 4

By the magic of DPAPI:

This class stores its data using the Data Protection API (DPAPI) protected memory model. In other words, data is always in its encrypted form while it is stored inside of a SecureString. The encryption key is managed by the local security authority subsystem (LSASS.EXE), and through the DPAPI, the data can be decrypted via interprocess communication.

Share:
11,583
sharptooth
Author by

sharptooth

Updated on July 12, 2022

Comments

  • sharptooth
    sharptooth almost 2 years

    According to MSDN SecureString contents is encrypted for additional safety so that if the program is swapped to disk the string contents can't be sniffed.

    How is such encryption possible I wonder? The algorithm would be fixed and therefore either well-known or deductible (say one of seven widely used in industry algorithms) and there must be a key somewhere in the program. So the attacker could fetch the encrypted string, fetch the key and decrypt the data.

    How can such encryption be useful?

  • Michael Brown
    Michael Brown over 9 years
    I think the key thing to take away from the posted article is "For the most part DAPI key management process is invisble and you generally don't need to worry about it". That right there makes me lean towards a custom solution. Good enough protection isn't always, well, good enough.
  • iokevins
    iokevins almost 7 years
    Note: As of 05/18/2017, article link returns 404: dsmyth.net/wiki/Print.aspx?Page=StudyNotes_DAPI