How to store the key used to encrypt files - c#

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;
}

Related

How to reset DPAPI key into the key ring?

I'm new to using DPAPI so this is something I've messed up on my app because I've been redeploying between my work laptop and my personal desktop so now the key that DPAPI is using to protect my data has changed between environments.
Now I'm getting the error that the key isn't in the key ring.
I hit this answer where a link provided discusses configuring key storage so I've updated my code to persist keys to file system (while I wait for sysadmin to get back so he can set up blob storage on azure as an alternative) and this should work fine for dev anyway.
var path = this.Environment.ContentRootPath + "/Data/Keys/";
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(path));
I can see the key files being created, but the error persists because I don't have the key that the app is looking for.
So how can I get it to generate/use/look for a new key here?
Oddly enough, it seems like completely reinitializing the app's database solved the problem.
My guess is it has something to do with the encrypted values that I stored in there (the DPAPI IDataProtector.Protect() output values). Specifically the fact that those values were encrypted with what I assume to be the key that the app was reporting couldn't be found.
Having reinitialized the database with new data, everything now works as expected.

How does System.Security.Cryptography.ProtectedData generate Unique Id

Im using System.Security.Cryptography.ProtectedData to Protect the license data before writing it to the registry.
ProtectData.Protect(Byte[], Byte[], DataProtectionScope.LocalMachine)
The Dataprotection scope is LocalMachine.
What are the parameters which are used by ProtectData to encrypt the string?
If i copy the encrypted string to another machine,will it work?
Some users are reporting licensing problems,is ProtectedData consistent?
Within LocalMachine scope, the protected data is associated with the machine context. Any process running on the computer can unprotect data. This enumeration value is usually used in server-specific applications that run on a server where untrusted users are not allowed access.
Caution The LocalMachine enumeration value allows multiple accounts to unprotect data. Use this value only when you trust every account on a computer. For most situations, you should use the CurrentUser value.
The encrypted data can only be decrypted on the same machine on which is encrypted.
DPAPI uses a MasterKey (512 bits of random data) to generate a session key for encryption and decryption. This means it will remain intact until reinstalling of OS.
https://msdn.microsoft.com/en-us/library/ms995355.aspx
Reflector shows that ProtectData.Protect is basically a wrapper for crypt32.dll's CryptProtectData() function.
From MSDN: (https://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx)
The CryptProtectData function performs encryption on the data in a
DATA_BLOB structure. Typically, only a user with the same logon
credential as the user who encrypted the data can decrypt the data. In
addition, the encryption and decryption usually must be done on the
same computer.

Decrypting the DUKPT TDES encrypted code of a Magnetic stripe reader in C#?

I am developing application for Magnetic Stripe reader, and the encrypted code format is DUKPT TDES Algorithm so my question is,
How to decrypt the encrypted code using DUKPT-TDES alogorithm in C#?
if any sample library available please post here.
According to Wikipedia, DUKPT is a Key Management method or process for assigning a unique Key for encryption of each transaction to be encrypted. As such it is not an encryption method, just a way of getting the key to use in the encryption (in your case the encryption method is Triple DES).
You will either have to make your own process for DUKPT, or find out how to use the process of the appropriate provider. Using your own should be OK (but not a trivial task, I guess) unless someone other than you needs to be able to decrypt the encrypted data: they will then need a way of getting hold of the correct key.

Encrypt Configuration

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.

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