I want to store couple of strings to be used in my application.
But I don't want to store it inside my Database or within Config.
The reason is that I want if someone copies the application from one system to another the strings should not be copied over.
Also, the strings can be manipulated at runtime through application.
What is the best way to do this?
A simple way to store user data is a file inside a user home directory. If the data is supposed for internal use inside your program only, one can use AppData\Local folder (e.g. "C:\\Users\\myuser\\AppData\\Local":
File.WriteAllText(
Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"MyCompany", "MyProduct", "MyStrings.txt"),
"Some strings");
The strings here are stored at "C:\\Users\\myuser\\AppData\\Local\\MyCompany\\MyProduct\\MyStrings.txt".
However, these files would not be readily visible by the user. So you should think about cleaning up such files when they are no longer needed.
One way to do that would be by encrypting your string using a key which is local to that machine e.g. MAC address, while saving it on the machine. Obviously to use it, you will have to read it and then decrypt it using the same key.
This way even if a string is copied over to another system, the new system will not be able to decrypt and use the string, as it does not have the same key as the original machine.
This solution is independent of whether you decide to store the string in bin or app data or elsewhere on the system.
Simple solution, create a file in user document and store the strings there. It is simple and easy to implement but it does not provide any kind of security. If you are going to store sensitive information then any one can read it. Also the user can delete the file which will result in file not found exception.
Second option is to write it on registry. It is neither hard not simple. Registry will solve the security problem with file. User will not accidentally delete the registry.
You can use the registry for things like that.
I have an Registry-Helper-Class to perform actions like this:
public class RegistryUtils
{
public static string Read(string subKey, string keyName)
{
RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(subKey, true);
if (registryKey == null)
{
registryKey = Registry.CurrentUser.CreateSubKey(subKey, true);
}
var keyValue = registryKey.GetValue(keyName);
registryKey.Close();
return keyValue.ToString();
}
public static void Write(string subKey, string keyName, string keyValue)
{
RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(subKey, true);
if (registryKey == null)
{
registryKey = Registry.CurrentUser.CreateSubKey(subKey, true);
}
registryKey.SetValue(keyName, keyValue);
registryKey.Close();
}
}
Then you can use the class for storing things like this:
var storedValue = RegistryUtils.Read("MY_COMPANY/MY_PRODUCT","MY_STORED_VALUE");
RegistryUtils.Write("MY_COMPANY/MY_PRODUCT", "MY_STORED_VALUE", storedValue);
You can use this to store any kind of value, not only string. But this should not be used for sensitive data, because the user can read and write the values of the registry with the registryeditor.
Related
I am using ini file to store my configuration in my c# gui.
but when i start my gui again , and save the configuration, the previous saved configuration gets overwritten.
IS there a way to keep on saving configurations ?
You want to use an app.config file instead of your .ini. You access the settings in it using the ConfigurationManager from the System.Configuration namespace. You can even create custom configuration sections by creating classes that inherit from ConfigurationSection. That will give you intellisense support of your config file, as well.
One example of that (it's using asp.net, but it works for any .net code) is here.
Edit: Re-reading your question, I'm unclear on if you're trying to save application settings (app.config), or if you're trying to save session data to disk (saving records or serializing objects). If the former, look at app.config. You can even have multiple items that set the same "settings" but with different values (such as having multiple SQL Connection strings) and then call them by some parameter you obtain from a user.
If you're trying to save session data/state, then you want to serialize your objects- look into serialization/deserialization (many options available there) and the System.IO namespace for persisting to disk.
The only way to prevent overwriting the same file each time is to make the file name unique e.g.
FileName<TimeStamp>.ini
Or
FileName<Guid>.ini
Or you could even do what windows does with duplicate files and check how many already exist and append a new number onto the end e.g.
FileName.ini
FileName1.ini
FileName2.ini
Personally I would go with the timestamp/GUID approach. Here's some example code
class Program
{
static void Main()
{
for (int i = 0; i <= 10; i++)
{
SaveConfiguration();
Thread.Sleep(500);
}
}
private static void SaveConfiguration()
{
string fileName = System.IO.Path.Combine(#"Config\File\Dir", String.Format("Config{0:yyyyMMddHHmmss}.ini", DateTime.UtcNow));
System.IO.File.WriteAllText(fileName, "File contents");
}
}
I'm a newbie to Windows Forms.
I'm designing an Windows Application in .Net Framework 2.0 in which,
I need to Store a UserName and Password somewhere in the System and access them every time I open My Application and Some times I need to change those credentials on User command.
I heard registry is the Best way in doing so. I know Nothing About Using Registry in C# .Net.
So Can you Help me in
How To Get Values which are In Registry, and how to Set a Value to Registry. ??
I'm Using .Net Framework 2.0
The subject is very broad. You should start reading on MSDN about the class
Microsoft.Win32.RegistryKey
But I really suggest to avoid the registry altogether.
Allowing the registry to store configuration info for normal applications has been a mistake from the start by Microsoft.
You could write a simple hashing function, apply it to your username and password and store the result in a file located in the ApplicationData folder.
At the next run check if the file exist, read it and compare its content with the hashing of username and password.
Here a rough example, just to let you start on your own code.
private void button1_Click(object sender, EventArgs e)
{
string user = "Steve";
string pass = "MyPass";
string hashedUser = GetHashedText(user);
string hashedPass = GetHashedText(pass);
string file = Path.Combine(Environment.GetFolderPath
(Environment.SpecialFolder.ApplicationData),
"MyKeys.txt");
if (File.Exists(file))
{
using (StreamReader sr = new StreamReader(file))
{
string recordedUser = sr.ReadLine();
string recordedPass = sr.ReadLine();
if (recordedUser == user && recordedPass == pass)
MessageBox.Show("User validated");
else
MessageBox.Show("Invalid user");
}
}
else
{
using (StreamWriter sw = new StreamWriter(file, false))
{
sw.WriteLine(hashedUser);
sw.WriteLine(hashedPass);
}
}
}
private string GetHashedText(string inputData)
{
byte[] tmpSource;
byte[] tmpData;
tmpSource = ASCIIEncoding.ASCII.GetBytes(inputData);
tmpData = new MD5CryptoServiceProvider().ComputeHash(tmpSource);
return Convert.ToBase64String(tmpData);
}
EDIT: Based on your comment, it seems that you need a crypt and decrypt function. The code below is taken and adapted from the Extension Overflow, where you can find other useful methods.
Now, before write to disk, call the Encrypt method with the string to encrypt and a key. After reading, call the Decrypt method passing the crypted text and the secret key.
string cryptedUser = Encrypt(user, "your_secret_key_ABCDEFG");
....
public string Encrypt(string stringToEncrypt, string key)
{
if (string.IsNullOrEmpty(stringToEncrypt))
throw new ArgumentException("An empty string value cannot be encrypted.");
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Cannot encrypt using an empty key.");
CspParameters cspp = new CspParameters();
cspp.KeyContainerName = key;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
byte[] bytes = rsa.Encrypt(UTF8Encoding.UTF8.GetBytes(stringToEncrypt), true);
return BitConverter.ToString(bytes);
}
string clearText = Decrypt(cryptedText, "your_secret_key_ABCDEFG");
....
public string Decrypt(string stringToDecrypt, string key)
{
string result = null;
if (string.IsNullOrEmpty(stringToDecrypt))
throw new ArgumentException("An empty string value cannot be encrypted.");
if (string.IsNullOrEmpty(key))
throw new ArgumentException("Cannot decrypt using an empty key");
try
{
CspParameters cspp = new CspParameters();
cspp.KeyContainerName = key;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
string[] decryptArray = stringToDecrypt.Split(new string[] { "-" },
StringSplitOptions.None);
byte[] decryptByteArray = Array.ConvertAll<string, byte>
(decryptArray, (s => Convert.ToByte(byte.Parse(s,
System.Globalization.NumberStyles.HexNumber))));
byte[] bytes = rsa.Decrypt(decryptByteArray, true);
result = System.Text.UTF8Encoding.UTF8.GetString(bytes);
}
finally
{
// no need for further processing
}
return result;
}
Of course, I assume that the security level required by your application allows that username ans passwords will be stored in the local system. (And as you know, everything that is stored on the local system is not very secure)
Check this tutorial with read, write and delete function for registry
Read, write and delete from registry with C#
Here is a good tutorial that will explain read/write to registry.
http://www.switchonthecode.com/tutorials/csharp-snippet-tutorial-editing-the-windows-registry
There are few more things you need to know about registry.
Registry consists of five sections of which HKEY_CURRENT_USER stores the settings of currently logged in user. It is recommended that you store the settings under this key. Settings are stored generally in HKEY_CURRENT_USER/Software//
You can store machine wide settings (applicable to all users using the computer) under HKEY_LOCAL_MACHINE key. However, read/write operations to this requires administrative rights. Your application must be running in administrator privilege to write to this key.
Make sure that your registry reading mechanism returns default values if it is not found in the registry as well as write the default values to registry. This way, you will never run out of setting values.
Registry can be edited and can be read. If you are planning to store username/password combination in registry, make sure you encrypt it before you store it. Further, to make sure that it is not used on any other computer also, you should encrypt it with some machine specific information.
Hope this helps you.
You could try using IsolatedStorage. MSDN Blurb, code sample, and (given you're storing user credentials) an encryption sample. I've linked .net 2.0 samples where possible.
Storing application data in the registry has become unpopular since there are easier alternatives and using the registry can hurt the performance of your users' computers.
I've never used the registry but first thing that comes up on google is this. Seems like fairly easy to understand so have fun with it :)
doing it the registry way is the wrong way to go, , i believe do a config file and read this config is much better way to go. but anyway here how you do registry thing
http://www.codeproject.com/Articles/3389/Read-write-and-delete-from-registry-with-C
You need to ask yourself a couple of questions:
Should only one user be able to use the uid/password?
How safe should the password be stored?
It's quite easy to store information in the registry.
http://msdn.microsoft.com/en-us/library/microsoft.win32.registry.aspx
If you just want to store it for one user, store it under HKEY_CURRENT_USER/software/your_company/your_product otherwize store it under HKEY_LOCAL_MACHINE/software/your_company/your_product.
If your password is to be stored safely, there are safer solutions than the registry.
I want to be able to detect when a critical configuration file has been changed.
I've used Configuration Section Designer to create a simple configuration file but now I cannot find an easy way to encrypt the result or add a value to it to check that it has been changed.
I want to be able to either prevent unauthorized users from changing the config file or at least know if the file has been changed.
If authorized users can change the configuration file, a high-level approach would be use an asymmetric key to sign the file. Only authorized individuals with access to the private key would be able to generate the hash, but the application could verify the legitimacy of the hash (and thus the file itself) with only the public key. One quick implementation follows.
This implementation requires generation of three files:
The configuration file you want to sign.
A file accessible to the application that contains the configuration file hash.
A private configuration file that contains the private key parameters.
Files (1) and (2) are accessed by the application. File (3) is confidential, restricted to authorized users.
The basic mechanism is this:
Generate an RSA key pair, and save the public and private key information. Private key information saved into File (3), and public key information is incorporated into the application. This step is performed only once.
Whenever a configuration file is changed, file (3) is used to sign the file's SHA1 hash. The hash is saved into file (2).
Whenever the program loads the configuration file, it generates the configuration file hash, and uses the public key to verify the signature. If the signatures match, it continues; if they do not match, it throws an exception.
1. Generating the RSA key pair
The RSA key data can be generated as XML:
(use System.Security.Cryptography)
var csp = new RSACryptoServiceProvider();
string publicXml = csp.ToXmlString(false);
string privateXml = csp.ToXmlString(true);
This produces XML data in the following format.
publicXML:
<RSAKeyValue>
<Modulus>oQKZR9hHrqm1tauCFYpbFlwyRNIHeyc2HCX+5htF/oc1x8Nk8i+itTzwRlgQG1cICO6lX
A+J9/OO2x2b9JILtk2tQow10xJdIsuiBeRwe7wJRdS8+l21F/JPY0eu/xiKQy
ukzEWLjIxGX7UXb9e4ltIxyRUUhk5G/ia1trcxfBc=
</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
privateXml:
<RSAKeyValue><Modulus>oQKZR9hHrqm1tauCFYpbFlwyRNIHeyc2HCX+5htF/oc1x8Nk8
i+itTzwRlgQG1cICO6lXA+J9/OO2x2b9JILtk2tQow10xJdIsuiBeRwe7wJRdS8+l21F/JPY0eu/xiKQ
yukzEWLjIxGX7UXb9e4ltIxyRUUhk5G/ia1trcxfBc=</Modulus><Exponent>AQAB</Exponent>
<P>zpFEWa7ave3wHL7pw7pSG0KXDPRwhCzU1Z5/fLoqSrPQzbkRqU+cwDVO/6IId3HdeXE09kVIu9/HBId
vupnY9w==</P><Q>x4pmqkmB7i8g9d3G6RSeZWYde8VOS5/OHUKgM6VrlQhgyrATpxGWAzJAe5eNO2BU
axNO8fZPe+lUSCJgY6TN4Q==</Q><DP>jaNL05ayhDLHRl6dmUiDjg+N1SMyl17KHSON1O8tmoVLchQp
CQf+ukiTP3NSDNy1eNTn9MkzAyeAphlbwf5Fpw==</DP><DQ>HhmUjw9zmBhn4m7H+JTxp94ViHwk6Wd
70hIg1GmZpuuSnkCdVlBizqyf6YTc+x323ggVmo5LQyfZXOBCpgVQQQ==</DQ><InverseQ>iO0CKRGB
2ULS6is/SwonqJw5fBsI9HTzx8rmKGA189dwlLGJSJuQo8uWmrLYhuo22BAqd0lMqxlKCHv6leeGPw==
</InverseQ><D>RSLliJkRJqnO0cRkZjVzqWVLXIvHFJWgwXN7QXlik8mhSTbYqLnVpvcUwU/dErBLTf
KTZLVza9nUdLgBGIKBrkbIqIWixq1fQ3zsEkyB/FQxwhIerTrhHyPzR+i3+5mduqQ7EBTj64u6STUf0y
TXHW2FYlfAinNz+K3iQFFarEE=</D></RSAKeyValue>
The private key strings should be saved (through any mechanism) to File (3) (private key). The application that is confirming the file's integrity will need the public key string (discussed later in step 3).
2. Signing the configuration file
To sign the configuration file, you will need the Private key Xml string generated in step (1).
private byte[] GetFileSha1Hash(string file)
{
using (var fs = new FileStream(
file, FileMode.Open))
{
return new SHA1CryptoServiceProvider().ComputeHash(fs);
}
}
static string GetConfigurationFileSignature(string configfile, string privateXml)
{
var p = new RSACryptoServiceProvider();
p.FromXmlString(privateXml);
byte[] signature = p.SignHash(GetFileSha1Hash(configfile),
CryptoConfig.MapNameToOID("SHA1"));
return Convert.ToBase64String(signature)
}
Calling GetConfigurationFileSignature will return a base64-encoded string. Save this string into File (2), where it will be referenced by the application.
3. Check the configuration file integrity
When the configuration file is loaded, the application should check the configuration file signature against the digital signature. The public key should be stored within the application rather than in a configuration file -- otherwise, the attacker can simply overwrite the public key in the configuration file with one for which he/she knows the corresponding private key pair.
static bool VerifyConfigurationFileSignature(string fileName, string publicXml, string signature)
{
var p = new RSACryptoServiceProvider();
p.FromXmlString(publicXml);
return p.VerifyHash(
GetFileSha1Hash(fileName),
CryptoConfig.MapNameToOID("SHA1"),
Convert.FromBase64String(signature));
}
(Note: you can use AppDomain.CurrentDomain.SetupInformation.ConfigurationFile to get the path of the current configuration file.)
When the application loads, it can make a call to VerifyConfigurationFileSignature with the path to the configuration file, public key XML data, and known signature. If this method returns false, it indicates the file has been tampered with; if it returns true, it is evidence that the file is legitimate.
Final Notes
The cryptography only ensures that the generated digital signature was generated with the private key. An attacker may still be able to override the application's verification logic to read malicious configuration data.
Any change to the configuration file (including adding comments, whitespace, etc.) will result in the hash becoming invalid. A more specialized implementation of GetFileSha1Hash might search for specific key/value pairs in the XML and sign only that data, allowing other modifications to the configuration file.
Including the hash itself in the XML file is not possible with the above implementation of GetFileSha1Hash, since updating the hash itself in the file would render the prior hash invalid. A specialized implementation of GetFileSha1Hash can ignore the generated hash value in generating the configuration file hash, thus preventing the need for separate configuration files.
A common approach to determining whether something has changes is to take a 'hash', for example, you could take an MD5 hash of the configuration, or part of it, then check against this has each time it is loaded in order to determine if it has been changed.
I am having an xml file like:
<CurrentProject>
// Elements like
// last opened project file to reopen it when app starts
// and more global project independend settings
</CurrentProject>
Now I asked myself wether I should deliver this xml file with above empty elements with the installer for my app or should I create this file on the fly on application start if it does not exist else read the values from it.
Consider also that the user could delete this file and that should my application not prevent from working anymore.
What is better and why?
UPDATE:
What I did felt ok for me so I post my code here :) It just creates the xml + structure on the fly with some security checks...
public ProjectService(IProjectDataProvider provider)
{
_provider = provider;
string applicationPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
_projectPath = Path.Combine(applicationPath,#"TBM\Settings.XML");
if (!File.Exists(_projectPath))
{
string dirPath = Path.Combine(applicationPath, #"TBM");
if (!Directory.Exists(dirPath))
Directory.CreateDirectory(dirPath);
using (var stream = File.Create(_projectPath))
{
XElement projectElement = new XElement("Project");
projectElement.Add(new XElement("DatabasePath"));
projectElement.Save(stream, SaveOptions.DisableFormatting);
}
}
}
In a similar scenario, I recently went for creating the initial file on the fly. The main reason I chose this was the fact that I wasn't depending on this file being there and being valid. As this was a file that's often read from/written to, there's a chance that it could get corrupted (e.g. if the power is lost while the file is being written).
In my code I attempted to open this file for reading and then read the data. If anywhere during these steps I encountered an error, I simply recreated the file with default values and displayed a corresponding message to the user.
In my C# application I need to create a .resx file of strings customized for every customer.
What I want to do is avoid recompiling the entire project every time I have to provide my application to my customer, so I need to dynamic access to this string.
So, how can I access (during the app execution) to a resx file if I kwow the file name only on the execution time?
Since now I write something similar:
Properties.Resources.MyString1
where Resource is my Resource.resx file.
But I need something like this:
GetStringFromDynamicResourceFile("MyFile.resx", "MyString1");
Is it possible?
Thanks
Mark
Will something like this help in your case?
Dictionary<string, string> resourceMap = new Dictionary<string, string>();
public static void Func(string fileName)
{
ResXResourceReader rsxr = new ResXResourceReader(fileName);
foreach (DictionaryEntry d in rsxr)
{
resourceMap.Add(d.Key.ToString(),d.Value.ToString());
}
rsxr.Close();
}
public string GetResource(string resourceId)
{
return resourceMap[resourceId];
}
You could put the needed resources into a separate DLL (one for each customer), then extract the resources dynamically using Reflection:
Assembly ass = Assembly.LoadFromFile("customer1.dll");
string s = ass.GetManifestResource("string1");
I may have the syntax wrong - it's early. One potential caveat here: accessing a DLL through Reflection will lock the DLL file for a length of time, which may block you from updating or replacing the DLL on the client's machine.
Of course it is possible. You need to read about ResouceSet class in msdn. And if you want to load .resx files directly, you can use ResxResourceSet.
Use LINQ to SQL instead of referencing System.Windows.Forms.ResXResourceReader class in your project.
public string GetStringFromDynamicResourceFile(string resxFileName, string resource)
{
return XDocument
.Load(resxFileName)
.Descendants()
.FirstOrDefault(_ => _.Attributes().Any(a => a.Value == resource))?
.Value;
}
And use it:
GetStringFromDynamicResourceFile("MyFile.resx", "MyString1");