How to store and retrieve credentials on Windows using C#
You can use the Windows Credential Management API. This way you will ask the user for the password only once and then store the password in Windows Credentials Manager.
Next time your application starts and it needs to use the password it will read it from Windows Credentials Manager. One can use the Windows Credential Management API directly using P/Invoke (credwrite, CredRead, example here) or via a C# wrapper CredentialManagement.
Sample usage using the NuGet CredentialManagement package:
public class PasswordRepository
{
private const string PasswordName = "ServerPassword";
public void SavePassword(string password)
{
using (var cred = new Credential())
{
cred.Password = password;
cred.Target = PasswordName;
cred.Type = CredentialType.Generic;
cred.PersistanceType = PersistanceType.LocalComputer;
cred.Save();
}
}
public string GetPassword()
{
using (var cred = new Credential())
{
cred.Target = PasswordName;
cred.Load();
return cred.Password;
}
}
}
I don't recommend storing passwords in files on client machines. Even if you encrypt the password, you will probably embed the decryption key in the application code which is not a good idea.
Retrieve credentials from Windows Credentials Store using C#
There is a NuGet library that I've been using, called CredentialManagement.
The usage is pretty simple. I wrapped it a little, but I probably didn't need to:
public static class CredentialUtil
{
public static UserPass GetCredential(string target)
{
var cm = new Credential {Target = target};
if (!cm.Load())
{
return null;
}
// UserPass is just a class with two string properties for user and pass
return new UserPass(cm.Username, cm.Password);
}
public static bool SetCredentials(
string target, string username, string password, PersistanceType persistenceType)
{
return new Credential {Target = target,
Username = username,
Password = password,
PersistanceType = persistenceType}.Save();
}
public static bool RemoveCredentials(string target)
{
return new Credential { Target = target }.Delete();
}
}
Sample usage:
CredentialUtil.SetCredentials("FOO", "john", "1234", PersistanceType.LocalComputer);
var userpass = CredentialUtil.GetCredential("FOO");
Console.WriteLine($"User: {userpass.Username} Password: {userpass.Password}");
CredentialUtil.RemoveCredentials("FOO");
Debug.Assert(CredentialUtil.GetCredential("FOO") == null);
If you're interested in implementing it yourself, browse the source:
http://credentialmanagement.codeplex.com/SourceControl/latest
The trick is that there is no C# API into the Credential Manager. This library wraps the other .dll entry points nicely. :-)
.NET Core: How to access Windows Credential Manager if running on Windows (otherwise ignore)?
I ended up using the Data Protection API for Windows (DPAPI) to store secrets in a file that is encrypted within the scope of the logged in user.
Encrypted storage of a password:
try
{
var passwordBytes = Encoding.UTF8.GetBytes(password);
var protectedPasswordBytes = ProtectedData.Protect(passwordBytes, null, DataProtectionScope.CurrentUser);
var protectedPasswordBytesBase64 = Convert.ToBase64String(protectedPasswordBytes);
File.WriteAllText(passwordFilePath, protectedPasswordBytesBase64);
} catch (PlatformNotSupportedException)
{
Debug.WriteLine("Could not store credentials");
}
Decryption:
if (File.Exists(passwordFilePath))
{
var protectedPasswordBytesBase64 = File.ReadAllText(passwordFilePath);
var protectedPasswordBytes = Convert.FromBase64String(protectedPasswordBytesBase64);
var passwordBytes = ProtectedData.Unprotect(protectedPasswordBytes, null, DataProtectionScope.CurrentUser);
password = Encoding.UTF8.GetString(passwordBytes);
}
(Only works on Windows, for other OSes I'll use other solutions.)
Access Windows Credentials in Credential Manager
There is a Nuget library called CredentialManagement http://nuget.org/packages/CredentialManagement/
from the answer here: Retrieve Credentials from Windows Credentials Store using C#
works perfectly
var cm = new Credential();
cm.Target = "mycredentialname";
if (!cm.Exists())
{
Console.WriteLine("cm is null");
}
cm.Load();
Console.WriteLine("Password: " + cm.Password);
Console.WriteLine("Username: " + cm.Username);
Retrieve Credentials from Windows generic Credentials Store using C# in ASP.net website under IIS
You should switch "Load User Profile" parameter of IIS App Pool to true. Then your code should start working.
How to save an email/password combination for windows program?
Uhm... Don't store in AppConfig settings.
If you cannot use a database for that (storing hashed and encrypted strings) get a new file for that, you can even protect it to allow only the service user account to read/modify it, or store it on the service profile directory (its user account profile directory)
I would do it using an ini file structure more easy to read than an xml, where each line contains something like
var mergedCredential = string.Format("{0}|{1}", "user@here.com" , "P@ssw0rd");
User1HashedCredentials=EncryptString("new username", mergedCredential);
I used a pipe to "merge" the credential as you can prevent users to use it on username
When you decrypt you split by "|"
var credentials = DecryptString("new username", User1HashedCredentials);
var splitted = credentials.Split('|');
Username = splitted[0]
Password = splitted[1]
An example of ini file:
[Users]
Count=5
[SendEmailSection]
User1=dsaa$#asdasd$#@rr==
User2=dggggjh7/sd$#@rr==
User3=dsaasd"/$%asdasd$#@rr==
User4=dsas/&"dasd$#@rr==
User5=dsAa&s3dasd$#@rr==
Which is easier to mantain and modify. You can even make your own specialized ini reader/writer Read sections, split by "="
Related Topics
How to Bind to a Dynamicresource So You Can Use a Converter or Stringformat, etc.? (Revision 4)
Is It Safe for Structs to Implement Interfaces
Conversion of a Decimal to Double Number in C# Results in a Difference
Intelligent Way of Removing Items from a List<T> While Enumerating in C#
Catching Exceptions with "Catch, When"
How to Click a Button in a Webbrowser Control
Singleton Httpclient VS Creating New Httpclient Request
External Handler for Msiexec Msisetexternalui
Convert Data Type from Inherited Classes in C#
System.Badimageformatexception: Reference Assemblies Should Not Be Loaded for Execution
How to Make Ef-Core Use a Guid Instead of String for Its Id/Primary Key
Rsa Encryption, Getting Bad Length
Change Pinned Taskbar Icon (Windows 7)
Getting Content/Message from Httpresponsemessage
Ensure That Httpconfiguration.Ensureinitialized()
I Have to Access/Commit/Update Svn Repository in Wpf Application Using Svn API or Libraries