I am using System.Configuration to encrypt and protect some passwords in a custom configuration section vis:-.
static public void SetPassAndProtectSection(string newPassword)
{
// Get the current configuration file.
System.Configuration.Configuration config =
ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
// Get the section.
MyAppProtectedSection section =
(MyAppProtectedSection)config.GetSection(DEFAULT_SECTION_NAME);
section.DBPassword = newPassword;
// Protect (encrypt)the section.
section.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
// Save the encrypted section.
section.SectionInformation.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}
This appears to work fine but I need some extra information for my documentation.
Where is the Key stored?
How long is the Key?
User level keys are stored at
\Documents and
Settings{UserName}\Application
Data\Microsoft\Crypto\RSA
Machine-level keys at
\Documents and Settings\All
Users\Application
Data\Microsoft\Crypto\RSA\MachineKeys
Yours is a user-level key.
I had a scenario where I needed to grant a local service account access to the RsaProtectedConfigurationProvider key on a Windows 2012 server.
In the end, granting access on C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys did the trick.
Related
I am creating a windows service that has to send an email out at specific intervals to various people. I am using an account on a server that I need to connect with securely.
I found this reference: https://nimblegecko.com/how-to-store-login-details-securely-in-application-config-file/
the code I was trying to implement is this:
var configuration = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
configuration.AppSettings.Settings["username"].Value = EncryptString("new username", configPassword);
configuration.AppSettings.Settings["password"].Value = EncryptString("new password", configPassword);
configuration.Save();
My question is encoding the username and password as fixed text still seems to result in the same exposure as hard-coding it right?
any help would greatly be appreciated?
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 "="
I do not suggest to store credential in app.config file. if you are planned to store there then you should store with proper encryption and decryption.
for you info you can refer this link
But I would suggest you to use window credential manager to store your password
for more details you can use their nuget package and their sample
Nuget
Another reference
Github
You can find it in your app's Preferences.
Right click on your project. Select add. Add .settings form. Then crate a table which contains email, password etc.
I'm having a problem with the windows service I work on currently. Basically I store some values in HKCU registry (from a GUI tool run as administrator) and from within that GUI I am starting a service. The service uses SYSTEM account to run and I believe that's my problem - I can't access registry keys stored with my GUI tool inside the service, as it points to a different HKCU!
How can I "redirect" the service to use the HKCU of the user it was stored with? (Actually I can pass a user name to the service or SID if someone will point me how to retrieve it in my GUI, but I don't know what should I use to "change" the user to point to the correct one)
#EDIT
I use a static class to access registry, it is used by both GUI and Service and the function to retrieve the base key is (rootKey is string variable holding the subkey name):
private static RegistryKey GetBaseKey(bool writable = false)
{
try
{
RegistryKey reg = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
RegistryKey rk = reg?.OpenSubKey("SOFTWARE", writable)?.OpenSubKey(rootKey, writable);
return rk;
}
catch (Exception ex)
{
// handle exceptions later
}
return null;
}
I have found WindowsIdentity class which can provide a handle (AccessToken) for current user, should I pass it as an argument to my service and use this handle to impersonate inside the service?
#EDIT2
I have done some stuff but it doesn't work. What I tried:
CurrentUserToken = WindowsIdentity.GetCurrent().Token; // to get current identity token
then with ServiceController.Start I added CurrentUserToken.ToString()
as an argument. Within my service I initialized RegistryUserToken (IntPtr) with the passed value and I'm stuck at:
WindowsIdentity RegUser = new WindowsIdentity(RegistryUserToken)
throwing exception
Invalid token for impersonation - it cannot be duplicated
I tried the same with AccessToken of current instance of WindowsIdentity - same exception thrown
Can I at all go that way? Or should I try something different??
I can give you two options: impersonate that user if you have their credentials or use idea that HKCU is a symbolic link for one of the keys under HKEY_USERS.
For impersonating you can see this link.
If you know the SID of that user, then you can find it in there. You can get the SID as so:
var account = new NTAccount("usernameThatYouNeed");
var identifier = (SecurityIdentifier)account.Translate(typeof(SecurityIdentifier));
var sid = identifier.Value;
I prefer impersonate. The second option is for case if you don't know that user's credentials.
I dislike second option because it requires administrative rights to write in someone else's account.
I needed to read registry of another user from a service. This is how I got it working, but in this case I know exact user name. Other answers here helped a lot. Username and path are whatever you need.
NTAccount f = new NTAccount("yourUserName");
SecurityIdentifier s = (SecurityIdentifier)f.Translate(typeof(SecurityIdentifier));
String sidString = s.ToString();
Microsoft.Win32.RegistryKey OurKey = Microsoft.Win32.Registry.Users;
OurKey = OurKey.OpenSubKey(sidString + "\\SOFTWARE\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Mappings", true);
if (OurKey != null) {
foreach (string Keyname in OurKey.GetSubKeyNames())
{
Alright, I've managed to solve it going a bit different way. I've added SID variable to my Registry class and if it's not null then I open Users Registry Hive instead of HKCU. First I retrieve current's user SID (within my GUI application) using:
WindowsIdentity.GetCurrent().User.ToString();
which I pass as an argument to my service and set it for Registry class.
I wrote a program that reads the UserPrincipal of an User in our Active Directory via PrincipalContext. For this the authentication of a privileged user is needed.
At the moment the password for this authentication is saved as plaintext in the source code. Because of security reasons a encrypted password should be saved in the source code or in a different file.
Is there a way to solve this?
const string domain = "";
const string rooOrganizationalUnit = "";
const string adDomain = "";
const string adUserName = "";
const string adPassword = "";
private static PrincipalContext GetPrincipalContext()
{
PrincipalContext principalContext;
principalContext = new PrincipalContext(ContextType.Domain, domain, rooOrganizationalUnit, ContextOptions.Negotiate, adUserName + "#" + adDomain, adPassword);
return principalContext;
}
(This snippet of code is originally taken from this site)
You don't want to store this in code either encrypted or not. One of the approaches will be to shift sensitive data off to a config file, type passwords in production only and encrypt that section in the application.
In a config file
<configuration>
<appSettings>
<add key="adPassword" value="this should be empty in source controll" />
</appSettings>
</configuration>
In code
const string adPassword = ConfigurationManager.AppSettings["adPassword"];
Notes
you'd want to encrypt config file section, something like this usually works
If you need to commit config file anyway, use config file transformation, and commit file as a template. Password will never be committed to source control
I tried to store user credential in registry editor.It was successfully worked.
RegistryKey key;
key = Registry.CurrentUser.CreateSubKey(#"SOFTWARE\\XXX\\Credential");
key.SetValue("Name", txtusername);
key.SetValue("Password", password);
key.Close();
how to store user credential securely in credential manager for wpf application?
If the credentials are to be used only from within the application itself then you can encrypt them and add them to your app.config file.
Create an application setting of type connectionstring and call it say myconnectionstring
Using Common.DbConnectionStringBuilder you can build then "connection string" with your username and password off the back of a dialog box that asks the user to enter them.
Then (in VB)
Dim config As System.Configuration.Configuration = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None)
Dim section As System.Configuration.ConnectionStringsSection = DirectCast(config.GetSection("connectionStrings"), System.Configuration.ConnectionStringsSection)
section.ConnectionStrings(My.Settings.ToString & ".myconnectionstring").ConnectionString = ConnectionString
section.SectionInformation.ProtectSection("DataProtectionConfigurationProvider")
config.Save(System.Configuration.ConfigurationSaveMode.Modified)
System.Configuration.ConfigurationManager.RefreshSection("connectionStrings")
This should save it encrypted in app.config
When read the data back out, .Net will take care of all of the decryption for you.
Simply create another Common.DbConnectionStringBuilder object, assign its connectionstring property to Configuration.ConfigurationManager.ConnectionStrings(My.Settings.ToString & ".myconnectionstring").connectionstring then read fields you need.
Hope this helps
If I have the DecryptionKey and ValidationKey set to AutoGenerate in the machineKey section of the machine.config, how do i look up from .NET the actual generated keys which have been created?
We wish to use the same keys to encrypt and validate our own cookies.
Any clues/tips gratefully received.
I know this doesn't answer your question but to encrypt and validate your own cookies you don't need to know the actual values of the DecryptionKey and the ValidationKey. Just use Encrypt and Decrypt methods:
var ticket = new FormsAuthenticationTicket(
1,
"username",
DateTime.Now,
DateTime.Now.AddMinutes(10),
false,
"some user data");
string encryptedTicked = FormsAuthentication.Encrypt(ticket);
// TODO: use the encrypted ticket in a cookie
Using AutoGenerate will just cause you grief as you, or rather your users, will too often encounter exceptions. Between the time when the data was encrypted and when it's decrypted the keys can and will change (application restart via app pool recycle, Web.config touched, etc.).