Is SecureString encrypted in .NET 5 and .NET Core running on Windows?

Viewed 827

Microsoft writes on its SecureString Documentation[1]:

On the Windows operating system, the contents of a SecureString instance's internal character array are encrypted.

On the other hand in Microsoft github repo[2] is written:

The contents of the array is unencrypted except on .NET Framework

So I'm wondering which statement is correct. Is SecureString encrypted based on the Operating System Windows (.NET Framework and .NET Core) or is it only encrypted in .NET Framework. How is SecureString encryption handled for .NET 5?

[1] https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring?view=netcore-3.0

[2] https://github.com/dotnet/platform-compat/blob/master/docs/DE0001.md

2 Answers

The source of SecureString has an EncryptionSupported Method (see below) which checks in combination with the CheckSupportedOnCurrentPlatform Method if encryption is supported, otherwise it will throw an exception.

Seems for me, that SecureString is supported on Windows unless if it runs on .NET Core or .NET Framework.

https://github.com/microsoft/referencesource/blob/master/mscorlib/system/security/securestring.cs

    [System.Security.SecurityCritical]  // auto-generated
        unsafe static bool EncryptionSupported() {
            // check if the enrypt/decrypt function is supported on current OS
            bool supported = true;                        
            try {
                Win32Native.SystemFunction041(
                    SafeBSTRHandle.Allocate(null , (int)Win32Native.CRYPTPROTECTMEMORY_BLOCK_SIZE),
                    Win32Native.CRYPTPROTECTMEMORY_BLOCK_SIZE, 
                    Win32Native.CRYPTPROTECTMEMORY_SAME_PROCESS);
            }
            catch (EntryPointNotFoundException) {
                supported = false;
            }            
            return supported;
        }


     private void CheckSupportedOnCurrentPlatform() {
            if( !supportedOnCurrentPlatform) {
                throw new NotSupportedException(Environment.GetResourceString("Arg_PlatformSecureString"));
            }                            
            Contract.EndContractBlock();
        }

SecureString is encrypted in .NET 5+ and in .NET Core running on Windows.

From .NET 5 documentation:

On the Windows operating system, the contents of a SecureString instance's internal character array are encrypted.

That page is however best read in entirety.

The same sentence is found in .NET Core documentation, too, both for .NET Core 3.0 and 2.0.


Microsoft recommends to store secrets outside of the process and to use opaque handles to access them, as preferable to using a SecureString. In other words, the main point of using a SecureString is pinning and as short duration of storing the secret in process memory in any form as possible, rather than encryption. The short "live" storage duration is of course the responsibility of the developer, not of SecureString itself.

Some use cases where SecureString's encryption can provide useful defense in depth is if the secret is arriving in small increments, relatively quickly (such as during keyboard password entry), and where the SecureString can be quickly used (e.g., re-protected and stored somewhere else) and disposed right after the last bit of the secret was received. In contrast, copying a pre-existing String into a SecureString in a loop is always rather pointless: you should be going to dispose the SecureString very soon anyway, and the secret is already spilt over to unpinned managed memory, so its plain text copies may live within the process forever even after you dispose the SecureString.

Related