How to reset DPAPI key into the key ring? - c#

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.

Related

Problems reading Windows Key on 64 bit machine

I want to read with a simple c# application the windows key from the registry. But on a x64 machine I recieve only BBBBB-BBBBB-BBBBB-BBBBB-BBBBB as the key and that is wrong... How can I fix that problem?
RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
RegistryKey subkey = key.OpenSubKey("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
Thanks!
According to this Web Site that makes CD Key recovery software and this Windows7Forums thread, the existance of all B's for the product ID is indicative of a MAK(Multiple Activation Key) key.
From First link:
The B’s means the cd key is not stored in your computer, so cannot be recovered. That can be due to a few reasons:
A MAK was used for activation;
SLMGR was used to remove the key from the windows registry,
or You’re running a pirated version of Windows.
From Second Link
This is a big problem when an administrator sets up many PCs with a
volume license key. Because everyone can extract the VLC key and use
it for additional installations. Because this reason the VLC key is
automatically deleted from the registry after activation. And after
this all key finder show only "not available" or
BBBBB-BBBBB-BBBBB-BBBBB-BBBBB. With command line: slmgr –dli you
can get a "Partial product key" – the last 5 characters of the product
key. This "Partial product key" is saved in encrypted form in the
certificate file "tokens.dat"
(C:\Windows\ServiceProfiles\NetworkService\AppData\Roaming\Microsoft\SoftwareProtectionPlatform\tokens.dat).
Everyone who fears that his key can be stolen can also delete manually
the product key from registry with this command line: slmgr –cpky
(cpky = clear product key = remove product key from the registry)
A quick web search shows many people with the same problem. One solution seems to be to get the DigitalProductID4 value if DigitalProductID is all B's.

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

CspParameter check if a keycontainername already exists

I've successfully signed my XML files using the RSACryptoServiceProvider. My key is stored in the Machine Key Store.
Now, I would like to check if the machinekeystore already contains the key that is related with the keycontainername or if the rsacryptoserviceprovider will need to create a new one.
How may I accomplish this?
Appreciate for your help!
Camille.
According to Key Storage and Retrieval, when Windows creates a Machine key store, it creates a file in the Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\Machine Keys directory. You could loop through the files and search for the file. See the example here called TryKeyContainerPermissionCheck for a way you might find the file.

Private key does not persist even with X509KeyStorageFlags.PersistKeySet

I have been searching for quite a while now but i am unable to find the answer to the following. I am storing a key pair in Windows Store, and recently started receiving the "Keyset does not exist" error. Investigating a bit further i found out it could be two things, 1 - The private key is not stored with the persist key set attribute (X509KeyStorageFlags.PersistKeySet) and 2 - access rights to the key. I have tried both 1 and 2 with no success on one machine (in my machine it works apparently). The strange thing is that when i look into Microsoft\Crypto\RSA\MachineKeys (and S-1-5-18) the key remains there but only for a period of time then it is deleted which means that it is not persisting.
//If decoded then save as RSACryptoServiceProvider
newCert.PrivateKey = DecodePrivateKey(privateKeyFile, pkPassword)
if (newCert.PrivateKey == null)
throw new System.NullReferenceException("Decoded private key resulted in a null reference. Unable to store certificate.");
byte[] pfx = newCert.Export(X509ContentType.Pfx);
newCert = new X509Certificate2(pfx, string.Empty, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
I am running this code on a WCF Service hosted on IIS, and the certificate is deleted even if i give permissions to Network Service, the AppPoolIdentity, my account, etc through MMC-CertMgr. Would anyone know why this happens?
Thanks in advance!
UPDATE:
I have just found out today that since i am doing this through a WCF service, the application pool is deleting the private key when it reaches its idle time limit so i am completely sure that it is the application pool the one disposing of the private key which causes the key to be deleted from the Microsoft\Crypto\RSA\MachineKeys and S-1-5-18 folders. Today i left a test running where i disabled Idle time shut down from the application pool bu i am still not sure if the private key will stop persisting with a restart or something like that?
Would anybody know how to make the application pool stop deleting my private keys?
I'm not sure for this particular case, but at work we have had problems using the RSACryptoServiceProvider in a Web Application context as well.
What fixed the problem for us was that we set "Load User Profile" on the corresponding ApplicationPool to "true". In our case we actually got PermissionDenied errors though, so not sure it will work for you.
Probably not the best answer, but if anyone needs to know the way i worked around this back then was to set the AppPoolIdentity to an Administrator account and set the "Idle Time-out (minutes)" value in IIS to 0. Only this way the AppPool will not delete the certificate files.

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