Encrypt Configuration - c#

The code on the Site here (shown below) encrypts app.config. I ran this on a button press to encrypt my config.
When am i supposed to run the code - (e.g at application start-up in case it is not already encrypted)?
In my bin folder i have 2 xml configuration files (Applicationname.exe.config and Applicationname.vshost.exe - this code only encrypts the first one of them - When i deploy my program how do i ensure that the my customer doesn't accidentally get the unencrypted file also as this would be a major issue ?(Or does the windows installer take care of ensuring this)?
C# Code
Configuration config = ConfigurationManager.OpenExeConfiguration(
ConfigurationUserLevel.None);
SectionInformation appSettingsSecInfo = config.GetSection(
"appSettings").SectionInformation;
if (!appSettingsSecInfo.IsProtected)
{
Console.WriteLine("The configuration file has NOT been protected!");
// Encrypt this section by using security provider
// (RsaProtectedConfigurationProvider or DpapiProtectedConfigurationProvider).
appSettingsSecInfo.ProtectSection("RsaProtectedConfigurationProvider");
appSettingsSecInfo.ForceSave = true;
config.Save(ConfigurationSaveMode.Full);
}

Please follow steps at this page. Author of the code snippet that you reference also does mention this page. But he is wrong about it not working on app.config files. All you have to do is rename yourapp.exe.config file to web.config, encrypt the sections you want and rename back to yourapp.exe.config.
Now to your scenario. The page that I have referenced also states the following:
You can easily export and import RSA keys from server to server. This makes RSA encryption particularly effective for encrypting configuration files used on multiple servers in a Web farm.
And it has a section about exporting and importing RSA keys.
So you could encrypt the configuration on your PC, export RSA key used for encryption and put it in your installer. The installer would then import the RSA encryption key into machine or user store on PC on which the application is being deployed.
But you should realize that when the application is starting, encrypted configuration has to be decrypted using private part of RSA encryption key (that we imported or it originated on the PC). Therefore if the application can get access to the private key so might the customer (I presume that the customer has physical access to the PC with your application). What you could do is use a user key container of user that only the application will run under for RSA encryption key but if the customer has administrator rights you will not be able to forbid him from decrypting the configuration.
So much for standard solutions. But you can always put sensitive data in a custom xml file, encrypt it and the encryption key compile into you application. Then the application would have to implement a logic to decrypt the xml itself. The customer would have to decompile your application to get to the RSA encryption key.

Related

Security gap: exe and exe.config on Visual Studio with SQL Connection(Open Password and Profile)

I have a question. On my c# application i made a release of an .exe for Windows. I have a connection to a MS SQL Database within and inside the release folder i have also a application.exe.config data.
My problem is that inside it i have the connection string of the connectivity to the MS SQL Server (IP, Profilename and Password) on normal uncripted words.
Is it possible do bind the exe.conf, or to crypt the datas? How i can solve this security problem
You could store an encrypted value in your config file and decrypt it using a specific algorithm in your application (more details on encryption here).
You could also try this trick to encrypt sections in your config file the same way it is done for Web applications.

How to encrypt app.config ( Without decrypt method )

I want to encrypt my "ConnectionString" settings which is located in app.config.
But at the Runtime, I want to use( read ConnectionString ) it directly, without decrypt it.
I mean, I don't want to anyone to decrypt the string. There should be NO decryption method.
I'm thinking; it should be like embed .net/asp.net/iis feature to use.
Like "Windows Login" ( you can enter it, use it, but you can't decrypt )
===
An Example Usage; You have small website with some critical data.
You have no money to buy private server,
so you are working on shared server, if the server hacked somehow,
you application and database will be stolen.
But if you put encrypted connectionstring in app.config,
This will be hard to decrpt it and see what is inside in Database.
Encrypting and decrypting configuration settings in a config file can be done from the command line using the aspnet_regiis.exe tool.
The details are described in the following MSDN article:
Encrypting and Decrypting Configuration Sections
As the tool is mainly intended to be used with Web applications, it expects the config file to be named 'web.config'. This means that you temporarily will have to rename your app.config file to web.config:
rename App.config web.config
aspnet_regiis -pef connectionStrings . -prov DataProtectionConfigurationProvider
rename web.config App.config
DPAPI might be a solution.
You can connect your usr/pwd/credentials to the machine. JGalloway knows more about this than I. JGalloway knows more about anything dotnet than I.
http://weblogs.asp.net/jgalloway/archive/2008/04/13/encrypting-passwords-in-a-net-app-config-file.aspx
If I haven't mixed things up this creates a usr/pwd combination that is bound to the very hardware of the machine. I.e. change network card and stuff might break. Also; one cannot create the usr/pwd/creds one machine and then transfer to another. In short this means that you have to do whatever you have to do on the production machine - might give you a headache if you are targeting continuous delivery.
Caveat: I haven't tried it myself. Instead I opted for a "regular" encryption. If someone got hold of my encrypted string and bytecode and reverse engineered it I would be smoked. But it was enough of security for me.

How to store the key used to encrypt files

I'm playing around with an app to backup files to "the cloud" :) and I want to encrypt the files before I store them. That part I have covered, but as this app will be monitoring folders for change and uploading the changed files I need to store the key that I use to encrypt the files with. The idea is that the user provides a password and a key is generated.
At the moment I'm using the .NET Framework to do the encryption. I'm using the RijndaelManaged class to encrypt/decrypt and the PasswordDeriveBytes class to get the key.
But how should I keep the key that is used for encrypting the files? I also want the program start to with Windows and not need to have the user enter their password again.
I'd recommend avoiding using asymmetric encryption for encryption of your files. Asymmetric encryption is significantly more expensive (computationally) than symmetric encryption algorithms of equal strength. For encrypting large files I'd recommend AES over RSA any day.
As to your question - the Data Protection API (DPAPI) Gaurav mentions is your best bet on Windows. How to: Use Data Protection
DPAPI offers ProtectedMemory and ProtectedData. The former allowing you to protect secrets in memory, the latter affords protection for secrets persisted to disk. The API takes care of encryption & decryption for you, and (depending on the specified scope) will protect your data from access/decryption by other users or on other machines.
To use DPAPI in your scenario, I'd recommend taking the users password, generating a symmetric encryption key (e.g. PasswordDeriveBytes), storing that using DPAPI and restricting access to the current user.
Your application can use that key to encrypt all uploads. Your application can obtain the key without re-prompting the user, and the key could be regenerated by the user on a new system.
One downside would be that a malicious application also executed by the same user could potentially obtain the secret key. To protect against this scenario additional entropy (effectively a salt) must be provided in Protect & Unprotect. However implementing this will likely stray from your objective - because now you'll need to prompt the user for something that seems an awful lot like a password.
Also: interesting reading:
You may also find this post from Backblaze an interesting read. Although they do not explain how they support your scenario (encrypted uploads that the cloud provider cannot decipher - only that they offer such a service):
http://blog.backblaze.com/2008/11/12/how-to-make-strong-encryption-easy-to-use/
Disclaimer: I am a satisfied Backblaze customer, but am in no other way affiliated with their service.
PS: Do take the time to mark acceptable answers. The community will reward you.
I suggest you to use asymmetric encryption like I described here. That will allow you to only have one single private key to protect (and backup) even while every file will be encrypted with a different symmetric key.
You can also let Windows (actually CryptoAPI) protect the key using a CspParameters (and the right flags) with the RSACryptoServiceProvider. Depending on your flags you can have the key will be available for the logged on user (so it gets as secure as the user login password).
DPAPI was designed to solve this challenge.
I concur with the DPAPI suggestion. Here's some code to demonstrate how to use the ProtectedData class. This isn't exactly germane for your exact scenario, but you can extrapolate.
byte[] GetEncryptionKey()
{
var path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
AppDomain.CurrentDomain.FriendlyName,
"nothing interesting... move along",
"top secret encryption key");
Debug.WriteLine("Encryption Key File: " + path);
var file = new FileInfo(path);
if (!file.Directory.Exists)
file.Directory.Create();
// determine if current user of machine
// or any user of machine can decrypt the key
var scope = DataProtectionScope.CurrentUser;
// make it a bit tougher to decrypt
var entropy = Encoding.UTF8.GetBytes("correct horse battery staple :)");
if (file.Exists)
{
return ProtectedData.Unprotect(
File.ReadAllBytes(path), entropy, scope);
}
// generate key
byte[] key;
using(var rng = RNGCryptoServiceProvider.Create())
key = rng.GetBytes(1024);
// encrypt the key
var encrypted = ProtectedData.Protect(key, entropy, scope);
// save for later use
File.WriteAllBytes(path, encrypted);
return key;
}

Decrypting ConnectionString

I've been reading about encryption and decryption of certain parts of the web.config for C#/ASP applications and I am successful in encrypting the connectionstring of the web.config for my application. My problem is decrypting. I'm using the standard code to encrypt and decrypt but it modifies the web.config. Locally it works fine since when it does modify the web.config I can save it and it will still run but when I upload it to a remote server then it doesn't work.
The error I'm getting is
Configuration Error Description: An error occurred during the
processing of a configuration file required to service this request.
Please review the specific error details below and modify your
configuration file appropriately.
Parser Error Message: Failed to decrypt using provider
'RsaProtectedConfigurationProvider'. Error message from the provider:
Bad Data
Encrypting
try
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
ConfigurationSection section = config.GetSection("connectionStrings");
if (!section.SectionInformation.IsProtected)
{
section.SectionInformation.ProtectSection("RSAProtectedConfigurationProvider");
config.Save();
}
catch (Exception ex)
{
}
Decrypting
Configuration config = WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
ConfigurationSection section = config.GetSection("connectionStrings");
if (section.SectionInformation.IsProtected)
{
section.SectionInformation.UnprotectSection();
config.Save();
}
I call the decrypting method whenever the page loads but it doesn't work and it gives me the error above.
I do not have access to the host server at all. So using the command line is not an option.
Make sure the same decryption key is available on the remote server that you have locally. This would be the machine key element.
You can create and export an RSA Key Container but you'll still need access to the remote server to import the container.
I don't believe that the machineKey element is relevant here BTW. From MSDN:
Key containers with local machine scope (useMachineContainer"true") are stored in a hidden folder at %ALLUSERSPROFILE%\Application Data\Microsoft\Crypto\RSA\MachineKeys
I'm guessing the scenario is you're trying to encrypt the web.config locally before pushing it to your hosting provider/remote server. Steve Rowbotham's answer on this question is correct in that you'll need the same RSA Key container on both your development machine and the remote server to be able to encrypt locally and decrypt remotely.
Can you take a different route and encrypt the web.config as part of your deployment process? We use MsDeploy to handle encrypting the config file during deployment and I can provide some sample code if you would like it.
Alternatively, when you application first loads (during the Application_Start event in global.asax) you could check if the connectionStrings section of the web.config is encrypted and then encrypt it. You shouldn't have to decrypt the web.config manually...

DataProtectionScope.CurrentUser encryption does not seem to work across machines

I'm trying to encrypt and decrypt some text file data using .NET's ProtectedData.Protect method. I'd like to be able to encrypt the text (and save it to a file) on one machine and decrypt the text on a different machine. The machines are both in the same domain and both running the same service under the same username so I thought using DataProtectionScope.CurrentUser would allow either service to encrypt and decrypt the file.
When service number two tries to decrypt the file, it throws a "key not valid for use in specified state". Other sites suggest that this kind of problem occurs when impersonation is not done correctly, but there is no impersonation. Both services run under the same AD account. It looks to me like the services are using different keys to encrypt the data but I don't know why this would happen as they are running under the same account.
Has anyone else encountered this kind of issue?
The code I'm using to encrypt and decypt is basically:
byte[] bytes = Encoding.Unicode.GetBytes(password);
byte[] protectedPassword = ProtectedData.Protect(bytes, null, DataProtectionScope.CurrentUser);
return Convert.ToBase64String(protectedPassword); //then I write this to a file
Thanks!
The user must have a Roaming Profile.
In the documentation for the Windows API underneath the DPAPI function, CryptProtectData function, there is this comment:
... decryption usually can only be done on the computer where the data was encrypted. However, a user with a roaming profile can decrypt the data from another computer on the network.

Categories

Resources