76

In our application we have a lot of sensitive configuration settings, which we are storing in a xml file which is again encrypted.

This secure file has to be decrypted in runtime and the configuration values read. but an issue arises that the key and initialization vector is hardcoded in the code and hence anyone can read it using Reflector.

What is the best way to store encryption keys in .NET so no one can read them using Reflector?

ganeshran
  • 3,512
  • 7
  • 41
  • 69
  • 3
    Is this a desktop application, or a web based one? If it's web based, is it distributed, or do you control the server? – Paddy Feb 11 '11 at 09:25
  • You should also point the level of security you want. There are lots of ways to hide something and no less ways to get that from the hidden corner .) – Ilya Dvorovoy Feb 11 '11 at 09:31
  • Maybe now RedGate are charging for Reflector it doesn't matter anymore.. ;-) – Grant Crofton Feb 11 '11 at 09:45
  • @Paddy: Its a desktop application. – ganeshran Feb 15 '11 at 11:11
  • What about storing the Key on a Hardware, here I am talking about Hardware Security Modules! Can we use it as best practices to hide the key? Can we store the key in configuration file and then encrypt the configuration file ? In my case I am talking about a Stand-alone .Net Application. – iamjayp Jul 07 '17 at 13:10

7 Answers7

26

If you want to protect your data from other users. Take a look at the ProtectedData class.

(Disclaimer: Protecting your data to create a copy protection scheme is not covered in this answer).

This classes uses the DPAPI from Windows, to encrypt and decrypt data on user or machine level.

Using ProtectedData/DPAPI frees you from handling keys and securing the data yourself. And you can choose to protect the data for the current user. The data can be read from different computers, by the same domain users.

If you want create your own key. You can create a key per user/machine, and store this key in the registry. Because the registry can be secured, only the current user can read the key back. I know the registry has bad karma, but is actually very good at storing data like this.

PS: Do not put the IV in your code. Create a new IV every time, and put it in front of the data.

GvS
  • 52,015
  • 16
  • 101
  • 139
  • DPAPI can also easy hacked after decompiling – Wowa Feb 11 '11 at 09:35
  • 1
    @Wowa: decompiling of what: your program? And then you can see that the application uses the DPAPI. This still does not allow to decrypt when you do not have the keys from the user. – GvS Feb 11 '11 at 09:40
  • I thought the key and IV had to be constant for decryption and encryption. Can the iv change and the text is still decryptable? I guess I need to do more reading into this. – ganeshran Feb 15 '11 at 11:12
  • 7
    You need to same IV to encrypt and decrypt, but it is not a secret like the key. So you can generate a different IV with every encryption run, and give the IV to the receiver. The easiest is to put the IV before the encrypted content. Creating a new IV with every run, will make it more difficult to find your key. – GvS Feb 15 '11 at 12:08
  • What if we have predefined configurations? (like connectionString) do we have to encrypt the config file on the target machine? – Hossein Shahdoost Nov 10 '15 at 06:46
  • @HosseinShahdoost If you use dpapi, and you have active directory setup, you can protect the config with that user and that user can decrypt it on any machine they sign into. – Wjdavis5 Apr 13 '16 at 15:37
  • @Wjdavis5 Thankx for your info but what if they don't have AD? – Hossein Shahdoost Apr 15 '16 at 05:46
  • 1
    @hossein what if they don't? You can still use dpapi. – Wjdavis5 Apr 15 '16 at 10:51
  • @Wowa how does decompiling the code help you hack dpapi? – Wjdavis5 Apr 15 '16 at 12:42
  • Creating a new key for each user would not be a practical way to protect the key – iamjayp Jul 10 '17 at 05:06
  • This would not work in a multiserver environment, right? – Mario Levrero Jul 31 '17 at 13:53
  • Pretty old question but one thing I couldn't understand is e.g. I want to store some predefined AES keys in my code (constant), the thing is it will be part of my source code, then protecting them doesn't make sense to me, because if some one de-compile then the AES keys would be visible. Am I missing something here? Or the storing part would be outside my application like in installer? – Muhammad Ummar Nov 14 '19 at 07:02
  • @GvS since this classes uses the DPAPI from Windows it is worth mentioning that this solution is not useful for other platforms. – badjuice Feb 24 '22 at 11:28
12

You should use the Machine Keystore, it's a secure storage especially for this purpose. For example:

CspParameters cspParams = new CspParameters(PROV_RSA_FULL, null, KEYNAME);

cspParams.Flags = CspProviderFlags.UseMachineKeyStore;

RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cspParams);

Where KEYNAME is a custom string that can be used to retrieve the key later on.

For more examples, see this question: How to store a public key in a machine-level RSA key container

Community
  • 1
  • 1
Maestro
  • 9,046
  • 15
  • 83
  • 116
11

If you can't read them in reflector, how do you expect the program to read them? You could obfuscate them by breaking them up and storing the parts all over the place, but (AFAIK) once you require your program to be able to read them, then anyone with access to your code can read them too.

Don't forget values in memory can be accessed as well (cough SecureString).

Massif
  • 4,327
  • 23
  • 25
4

When you install the application, make a new set of RSA keys, then encrypt the data with AES using the private key as the password. As Windows stores RSA private keys securely on the PC that created them, the data can only be decrypted by the computer that created the data because only that computer will have the necessary key.

DividedByZero
  • 4,333
  • 2
  • 19
  • 33
4

Generally, a new key and IV should be created for every session, and neither the key nor IV should be stored for use in a later session.

To communicate a symmetric key and IV to a remote party, you would usually encrypt the symmetric key and IV using asymmetric encryption. Sending these values across an insecure network without encrypting them is extremely unsafe, as anyone that intercepts these values can then decrypt your data. For more information on this process of encrypting and transferring the key and IV, see Creating a Cryptographic Scheme.

apros
  • 2,848
  • 3
  • 27
  • 31
1

What about storing the file encryption/decryption key on a remote server, getting it though a web service that would transfer it though https to the application? that way the key stay in the memory of the computer but is not into a source code file.

This requires to have connection to the key server by whoever runs the application though.

user1892410
  • 381
  • 5
  • 12
  • You are correct. But, we still can recover the key as it stays in the memory of computer that is RAM. It is still not an applicable method to protect the key. Also http is not secure. – iamjayp Jul 10 '17 at 05:03
0

It bears mentioning that any solution that is per machine or per user is not terribly useful for applications that store data in a database that is potentially to be read by multiple users on multiple machines during application runtime. Most use cases cannot make an assumption that data a given user posts is only expected to be read by him.

This is my best practice for storing and generating/using encryption keys in applications. Your mileage may vary if you have usage requirements that can't accommodate this scheme.

First, along with my application, I distribute an application-specific configurator to my customer. This configurator is run by my customer's administrator who installs the application and the database, which resides on a Microsoft SQL Server.

After running the installer, the admin runs my configurator. The configurator allows him to specify sensitive information, such as their SMTP server credentials needed for the application to send email, etc.

The configurator uses a private master key, which is hardcoded in a DLL. This embedded key is different per distribution. The sensitive information is encrypted and then stored in the registry by the configurator. The master key is also used to encrypt/decrypt other encryption keys that are generated at runtime to encrypt/decrypt application data.

At application runtime, another key is generated for general application data encryption - stuff like passwords and other sensitive info to be stored in the database in encrypted form. This key is encrypted using the master key from the DLL previously mentioned, and it is then stored in the registry as well.

Every time the application needs to encrypt or decrypt data to and from the database, it uses the master key to decrypt the application key. The application key is combined with a different IV each time. Each new IV is simply prepended to the data, as some of the other answers here have described.

When decrypting, the application simply clips the IV off the front of the data payload, and uses it along with the application key from the registry to decrypt the remainder of the payload.

By using this scheme, the only risk is that it could be read from memory. Secure strings can be used to minimize that risk if you're that concerned about it. Most of my clients don't expect their users to be hooking up to JTAG ports of motherboards and trying to read and decipher memory contents, but hey... your mileage may vary.