I have an application that requires a secure way to store its configuration. There are users that can change the configuration. I need some sort of signature scheme where I can verify that the config file has not changed with out a valid user. I had thought about using RSA, where the private key is encrypted with the users password, and the public key is used to sign the config. However there is nothing to prevent someone from changing the user file and adding their own public key, thus circumventing my security. Any ideas?
You could just keep the file encrypted, and only allow editing from within your application. This would prevent users from editing the configuration from any tool other than yours, which could do the authentication to verify that the user is a "valid user".
There is no way to fully secure a stand-alone Client application. The only way would be to do a checksum on the file and validate it to a/the server. The method of signing the file is less important than how you verify what is in fact signed.
A start to securing the client application is with Obfuscation. Thereafter your encryption is next in line.
For the actual signature, even a SHA
series of hashes should do the job for you. An example using SHA512 is as follows:
FileStream fs = new FileStream(@"<Path>", FileMode.Open);
using (SHA512Managed sha512 = new SHA512Managed ())
{
byte[] hash = sha512.ComputeHash(fs);
string formatted = string.Empty;
foreach (byte b in hash)
{
formatted += b.ToString("X2");
}
}
These contradicts:
- "I can verify that the config file has not changed with out a valid user"
- "there is nothing to prevent someone from changing the user file"
You should just find a way to protect your "user file" first. By encrypting it with a key nobody can edits (except determined crackers) or otherwise. And then your RSA scheme will work.
Do note that, however, there is NO way to protect an application that runs entirely on the client from a determined cracker.
For most applications, though, you DON'T need perfect security. Maybe you should think about how much security is actually "enough" for your application first.
If you, however, needed perfect security, then you might need to add a server-side component OR add human-intervention into the process such as having an administrator controls the user file.
Encrypt the "user file" with the admin's passwords. And then whenever someone wants to change the user file, the administrator's consent is then needed.
I think what I will do is keep a private key(A) in the office. I will ship the app with an public private pair(B), signed with the private(A) that only I know. I will use the public private pair(B) I ship to sign everything on the config files. Thus there will be a verifiable set of RSA keys(B), that can't be change, because the private key(A) used to verify them is in the office, and the public key(A) is hard coded.
Of all the methods listed, key management is the true weakness on a client machine. The key is required to decrypt. Using another key to encrypt that key is no stronger. Obfuscation is a start.
What I use is a separate assembly that contains our encryption code. The key is then stored via a technique called Steganography. I encode the key in the logo of application. This key is then encrypted using a known value of the software. In one case, it may be the checksum of a specific assembly. Thus anyone that makes any change to that file will break the system. This is by no means any more secure, but its all about hiding details. and raising the level of difficulty from casual to determined. From there, I then run the assembly through an obfuscator and string encryptor. This breaks Reflector with a crash when attempting to view the assembly and thus makes its more difficult to learn what is going on.
The issue with these strategies, is that if you attach an debugger then you get the data in the clear since you may store the values in a string after the encryption/decryption process. To combat this, but not eliminate, I use the System.Security.SecureString class and do not keep data in the clear.
The goal is to break reflector, stop simple attacks of just using the .NET Framework to decrypt the data, stop dictionary attacks by employing a random salt, allow easy string handling by URLEncoding the encrypted buffer, proper use of an Initialization Vector.