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
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.
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.
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;
}
}
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.
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.
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.