Saving a SecureString

17,015

Solution 1

There is no save support in SecureString, it's intended as a mechanism to protect a in-memory managed string and is only used for interfacing with unmanaged APIs. If a password was stored in a System.String instance, security would be less due to the nature of System.String. The existence of garbage collection and interning would keep the password in memory longer than necessary. Also due to the plethora of great debugging tools for .NET, it would be significantly easier to access the string through reflection or another .NET API even without the longer lifetime.

If you're going to save a password on the disk your security is pretty far compromised. If someone has physical access to the machine, or administrator level remote access, then the best you can do is make it more difficult, but never impossible. Use an encryption API, store it in a secure location, configure access rights.

All that aside, Merus, I'd suggest you try to improve the overall system because for a use-case like you're describing (assuming I understand it) you'd be better served to store a hash than the actual password.

Solution 2

You might want to look at comparing password hash.
You would have a salt made of username and probably some other constant, followed by the string. Then, you would pass that to a hashing algorithm, like SHA1*.
For instance,

using System.Security.Cryptography;

public byte[] GetPasswordHash(string username, string password, string salt)
{
    // get salted byte[] buffer, containing username, password and some (constant) salt
    byte[] buffer;
    using (MemoryStream stream = new MemoryStream())
    using (StreamWriter writer = new StreamWriter(stream))
    {
        writer.Write(salt);
        writer.Write(username);
        writer.Write(password);
        writer.Flush();

        buffer = stream.ToArray();
    }

    // create a hash
    SHA1 sha1 = SHA1.Create();
    return sha1.ComputeHash(buffer);
}

Then, you would compare the result for GetPasswordHash(username, expectedPassword, salt) to GetPasswordHash(username, givenPassword, salt).
If you implement your own user list with usernames and passwords, you might consider only saving the hash (GetPasswordHash(username, givenPassword, salt)) and comparing against the saved hash.

Solution 3

If you mean saving the SecureString's encrypted bytes then this will not work - the key for the SecureString is tied to the user and process. Read in those bytes in a different process or for a different user, and there's no way to decrypt the string.

Solution 4

This would defeat the point of a SecureString, which is guaranteed to reside in memory. So if you are saving it to file, you might as well save it as a normal string, since it is no longer "secure".

Solution 5

The SecureString is not serializable so you cannot just save it with some of the delivered serializers (binary, XML, etc.)

you also cannot just access e.g. a "Password" property from a securestring object as there is no such thing. you have to use Marshalling and a little bit of plumbing to do this. if you want to store user credentials somewhere I suggest encrypting them on your own as this eases later development. after evaluating the SecureString approach, we decided to implement something by ourselves, but these are just my 2 cents.

Share:
17,015
Merus
Author by

Merus

I'm a journeyman developer working mostly in C# and Rails. I'd like to pick up some other languages, and have been eyeing Python for a while.

Updated on June 24, 2022

Comments

  • Merus
    Merus about 2 years

    One of the feature requests I've got for the program I'm working on is to be able to save the list of credentials users enter in, so they can be shared around. The specific use case that inspired this request was using our program on a large corporate network, made up of fairly good LANs connected by a flaky WAN. The idea was that, instead of having our program beat against the WAN when it's down, they'd send a 'configuration' file containing the closely-guarded admin credentials, run it in each LAN and zip up the results and e-mail it back.

    Yeah.

    My initial instinct is to scoff at this request - saving passwords? really? and surely the network division of the company would prefer you to try and sell whatever WAN products they have - but it turns out one of the classes I use the credentials for can take a SecureString, and, well, it's always good to look out for ways you can save people some effort. That got me to wondering:

    Is it possible to save an encrypted SecureString, so that I can save the sensitive data to a file and open it up someplace else?

    What are your thoughts, Stack Overflow?

  • Merus
    Merus over 15 years
    I was hoping that SecureString would do the hash for me. I know better than to roll my own hashing function.
  • Kiquenet
    Kiquenet almost 12 years
    In powershell can save SecureString, any way using C# ?? stackoverflow.com/questions/11174425/…
  • Siva Sankaran
    Siva Sankaran over 11 years
    sometimes comparing the given password is not the task but the program itself want to use passwords to gain authorization in other system. Like a mail client use password to gain authorization in SMTP Server. what can we do in that situation
  • configurator
    configurator over 11 years
    @Sankaran: Each case has its own solution. Most modern APIs accept password hashes already; some have API keys so you don't even need to know the password's hash. To use older APIs which only support using the password directly, you'd have no choice but to store the password itself. In that case, I'd use some sort of encryption, although it's pretty much futile.
  • Joel Coehoorn
    Joel Coehoorn over 9 years
    MD5 is totally inappropriate as a hash algorithm choice. You need bcrypt or scrypt, or at least sha1 (and even that's not really recommended).
  • configurator
    configurator about 9 years
    @JoelCoehoorn: absolutely right. Back in '08 I didn't know that, I guess. I've updated the post accordingly to use SHA1 - because unlike bcrypt, SHA1 is built in to .Net.