views:

733

answers:

6

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?

+1  A: 

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.

Michael Burr
+1  A: 

You might want to take a look at the IsolatedStorageFileStream class. It specifies ways to write and store file data which can be accessed only by your assembly.

I don't think you can use SecureString on it though.

Jon Limjap
+1  A: 

th SecureString is not serializabl 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 Marshallig 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 ;)

Joachim Kerschbaumer
+3  A: 

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".

Spodi
+2  A: 

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 you're 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.

nedruod
I was hoping that SecureString would do the hash for me. I know better than to roll my own hashing function.
Merus
+2  A: 

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 MD5.
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
 MD5 md5 = MD5.Create();
 return md5.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.

configurator