views:

4652

answers:

9

I need to store and encrypt a password in a (preferably text) file, that I later need to be able to decrypt. The password is for another service that I use, and needs to be sent there in clear text (over SSL). This is not something I can change. What are best practices in this area? How can achieve some degree of protection of the password from malicious users?

My platform is WinForms with C#/.NET 3.5.

Thanks.

+1  A: 

Because you are using WinForms and .Net, your code is going to be visible in MSIL - even if obfuscated, and therefore your decryption code is visible.

Who are you trying to hide the password from? Is the user of the app not supposed to know the password?

I think you are going to need to do some user validation, and I would be tempted to put keys to the decryption in a separate database and provide some other mechanism to get that out which should require authentication. That way you can get the decryption code out of the winforms app.

I would also suggest a separate service which runs to regularly change the encryption decryption keys and updates all passwords in the database.

Sam Meldrum
+5  A: 

I am assuming that you want to encrypt the password as it will be on the users machine and they will (possibly) be able to find it and use it? If so you are basically screwed - no matter what you do, since it is in the users domain they will be able to get it and figure out the encryption and get the password for the encryption (remember that using Reflector - and it's clones - isn't out of the reach of most) and decrypt it and they have it. In short all you are doing is obfuscating the password, not securing it.

What I would recommend is actually move it out of the users control. For example put up a web service which communicates with the client and returns the password securely when requested. This also allows you to change the password, if needed in future as well as provides you with a way to validate legitimate users.

Robert MacLean
+1, but how should we secure access to the password-returning web service?
Matthew Murdoch
@Matthew any standard authentication system for services would work great.
Robert MacLean
@Robert: would you care to elaborate? If the user him/herself can just call the service, the security point is kind of moot. What am I not getting here? Thanks.
Eyvind
@Eyvind for example give all users a key (username/password, unique id what ever) and require that when the call is made to get the password, for example: public string GetPassword(string username, string password)The clients put their key in their app and it authenticates them so you know you can "trust" them. This also allows you to block users if needed in future. There is a lot out there on WCF/Web Service authentication: http://stackoverflow.com/search?q=web+service+wcf+authentication
Robert MacLean
Rather than returning the password to clients that then use it to connect directly to the third-party service, you might consider running an authenticated web service that proxies all client requests to the real service; your password to the third-party service is never sent to the client. This is more expensive for you and adds a little overhead to the calls, but gives the best security. Depends on the value of securing the password.
erickson
+1  A: 

Encrypted in AES if you must store it in a text file.

AES is better known as Rijndael in c#

http://www.obviex.com/samples/Encryption.aspx

Better place would be the registry, since it would protect other users of the machine getting to it.

Still not the best storing it anywhere that a user might be able to get to is dangerous a 1/2 way decent developer can load up your app in reflector and find your key.

Or there is System.Security.Cryptography.ProtectedData that someone else suggested.

The best you could do on a machine is create a certificate and encrypt/decrypt with it loaded and locked down in the machine's keystore. (Still have to deal with the certificate password being in your code)

Chad Grant
"Better place would be the registry, since it would protect other users of the machine getting to it." Storing in the registry vs a text file doesn't affect access by other users of the machine.
Joe
@Joe, the HKEY_CURRENT_USER is not accessible by other users of the machine. They have their own HKCU. Admin's excluded of course. http://en.wikipedia.org/wiki/Windows_registry And then there is this:http://blogs.msdn.com/bclteam/archive/2006/01/06/509867.aspx
Chad Grant
But you're right, I am not in love with my own answer, but with limited information of what he has to work with I am giving him options. Personally, I like using a webservice/aspx to proxy his password for the user, but then he's gotta get a SSL certificate etc..
Chad Grant
A: 

Do not store the password as part of the code. Aside from the issues of decompilation and relying on security through obscurity, if you change the password you need to recompile and redistribution your application.

Store the password as a webservice or in a database that the application has access to. You're communicating with a service over the web, so you will be connected, after all.

Unsliced
A: 

One of the most important thing is the permissions on the file. Even if the content is encrypted you need to make sure that only the processes that need access to the file can read it.

Dave Webb
+1  A: 

System.Security.Cryptography.ProtectedData in the System.Security assembly uses some Windows APIs to encrypt data with a password only it knows.

One possibly use of this would be to have a Windows service that actually does the operation requiring the password. The application that the user interacts with calls into the service via remoting or WCF. As long as the service used DataProtectionScope.CurrentUser and the service user is different from the logged on user, the password should be pretty safe.

This of course assumes that the users are running as limited users who cannot modify the service or run program as the service's user.

Austin
+1  A: 

Why you need to decrypt the password? Usually a salted hash of the password is stored and compared. If you encrypt/decrypt the password you have the password as plain text again and this is dangerous. The hash should be salted to avoid duplicated hash if the some users have the same passwords. For the salt you can take the user name.

HashAlgorithm hash = new SHA256Managed();
string password = "12345";
string salt = "UserName";

// compute hash of the password
byte[] plainTextBytes = Encoding.UTF8.GetBytes(password);
byte[] hashBytes = hash.ComputeHash(plainTextBytes);

// create salted byte array
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
byte[] plainTextWithSaltBytes = new byte[plainTextBytes.Length + saltBytes.Length];
for (int i = 0; i < plainTextBytes.Length; i++)
{
   plainTextWithSaltBytes[i] = plainTextBytes[i];
}

// compute salted hash
byte[] saltedHashBytes = hash.ComputeHash(plainTextWithSaltBytes);
string saltedHashValue = Convert.ToBase64String(saltedHashBytes);

You can calculate the salted hash of the password and store that within your file. During the authentication you calculate the hash from the user entries again and compare this hash with the stored password hash. Since it should be very difficult (its never impossible, always a matter of time) to get the plain text from a hash the password is protected from reading as plain text again.

Tip: Never store or send a password unencrypted. If you get a new password, encrypt is as soon as possible!

Enyra
As stated in the question, I must decrypt it because the service accepts only a password in unencrypted form.
Eyvind
If you can not avoid it, I would use AES, but be aware that any encryption key can be read from the assembly, so it's not really save.
Enyra
A: 

Since you must send the password in unencrypted form over the network, there is nothing you can do to protect it 100%.

AES is good enough if you need to store locally, and talking about disasms, network sniffers etc is not particulary good contra-argument becuase the same thing can be done with any program (sure, ASM is harder then CIL but its a minior point).

Such password protecting is good enough to prevent casual pick up, not to prevent decoding by proffesionals.

majkinetor
Like he said, it is encrypted via SSL
Chad Grant
The password is for another service that I use, and needs to be sent there in clear text (over SSL)
majkinetor
A: 

I just implemented something like this for storing a user supplied password. I converted the encrypted result to a base 64 encoded string, so that I could easily store it in my application's user settings.

From your question, it seems that your malicious user is actually using your application, so this will only provide obfuscation. Though no key would be revealed through the use of Reflector, the plain text would be visible in a debugger.

static byte[] entropy = { 65, 34, 87, 33 };

public string Password
{
    get
    {
        if (this.EncryptedPassword == string.Empty)
        {
            return string.Empty;
        }

        var encrypted = Convert.FromBase64String(this.EncryptedPassword);
        var data = ProtectedData.Unprotect(encrypted, entropy, DataProtectionScope.CurrentUser);
        var password = Encoding.UTF8.GetString(data);
        return password;
    }
    set
    {
        if (value == string.Empty)
        {
            this.EncryptedPassword = string.Empty;
            return;
        }

        var data = Encoding.UTF8.GetBytes(value);
        var encrypted = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser);
        var stored = Convert.ToBase64String(encrypted);
        this.EncryptedPassword = stored;
    }
}
Chris Ostler