RSACryptoServiceProvider(RSACryptoServiceProvider) constructor crashing in .NET 3.5 for certain key names

好久不见. 提交于 2019-12-14 03:42:40

问题


If you look at the code below it is doing nothing but creating a new instance of an RSACryptoServiceProvider. The key container name is initialized from a property that creates a name based on various parameters. I have added hardcoded values in this demo code.

The code is running on a Windows 2008 R2 server installation and has worked for months with a constant value being returned for the key container name.

Some days ago the code stopped working and we're facing the exception below. Using the key container name that has been used for months no longer works. The server has been rebooted, IIS has been restarted - no success. Only after changing the key name it has started to work again.

Can somebody explain why this is happening and how to fix it? As far as I can see, this code does not crete any persistent objects. Why would it still fail after a reboot? From MSDN (http://msdn.microsoft.com/de-de/library/ca5htw4f.aspx) I read that the constructor "constructor creates or reuses a key container specified using the KeyContainerName field". Does the "reuse" mean, it is caching the stuff somewhere and while doing that it crashed and is now stuck with a corrupt cached version? Also note that the same key name is currently still used on many other machines - no problems anywhere.

This is the line that is crashing:

using ( RSACryptoServiceProvider rsa = new RSACryptoServiceProvider( this.oCspParameters ) )
{
}

These are the CspParameters used:

private readonly CspParameters oCspParameters = new CspParameters
{
  Flags = CspProviderFlags.UseMachineKeyStore,
};

this.oCspParameters.KeyContainerName = oProfile.KeyName;

And that's the key name:

public string KeyName
{
    get
    {
        return string.Format( "API-{0}-v{1}", "TestClient", "1.0.0.0" );
    }
}

And finally the exception:

CryptographicException: An internal error occurred.
Service Operation: ISessionService.Identify #f173250b-d7ac-45d5-98ed-7fffcf37d95a
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)

回答1:


As far as I can see, this code does not crete any persistent objects

The following code will create the key container if it doesn't already exist:

using ( RSACryptoServiceProvider rsa = new RSACryptoServiceProvider( this.oCspParameters ) ) 
{ 
} 

If you want to force use of an existing key, you should specify:

cp.Flags = CspProviderFlags.NoPrompt | CspProviderFlags.UseExistingKey | CspProviderFlags.UseMachineKeyStore;

Does the "reuse" mean, it is caching the stuff somewhere and while doing that it crashed and is now stuck with a corrupt cached version?

It will reuse a key stored in the Microsoft\Crypto\RSA\MachineKeys\ subfolder of the Environment.SpecialFolder.CommonApplicationData folder, if it exists and you have permission to access it. Otherwise it will attempt to create it.

Perhaps there is a key there that you don't have permission to access?

The file names of the key containers use a generated unique id (CspKeyContainerInfo.UniqueKeyContainerName), but you can examine the file contents with a text editor, and the key container name is in the first few characters of the file.

Once you have located the offending file, you can examine its permissions, and perhaps delete it so it can be recreated.

From comments:

How can I force it then to NOT do so or how can I delete the container?

You can delete a existing key container (provided you have the necessary permissions) when you've finished with it with the following code:

CspParameters cp = new CspParameters();
cp.Flags = CspProviderFlags.NoPrompt | CspProviderFlags.UseExistingKey | 
                   CspProviderFlags.UseMachineKeyStore;
cp.KeyContainerName = containerName;

using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp))
{
    rsa.PersistKeyInCsp = false;
}

I haven't tried it, but perhaps setting PersistKeyInCsp=false when creating the key would prevent if from being persisted.

However none of the above explains why you are no longer able to access a key that you were previously using successfully. The most obvious reason would be permissions - I know you get a CryptographicException if you attempt to access a key container that you're not authorized to access, but I don't know if you would expect to get a more explicit error message than "An internal error occurred". The first thing I'd do would be to check the ACL on the key container file. Perhaps you have two instances of your application running under different identities that attempt to create the key container - and the key container created by identity 1 is not accessible by identity 2.

Finally as you seem to suggest you don't want to persist the key container, why would you use the machine store?




回答2:


I recently discovered this question while helping another dev resolve this issue on his local machine.

In our scenario, we were using RSA to encrypt a password. The code in question had worked in the application for years. Suddenly, the RSACryptoServiceProvider constructor began to experience errors on one developer's machine. The message was the ambiguous and dreaded "Key not valid for use in specified state."

From Joe's answer above, we found the stored the keys in a location like:

C:\Users\<user name>\AppData\Roaming\Microsoft\Crypto\RSA\

By opening the key files in notepad++, we were able to find the name of our key at the top of one of the files.

Deleting the offending file allowed the developer to run the application successfully again - the file was regenerated the next time we called the constructor.

I am still not sure what happened, but it appears the original key file had somehow become corrupted.



来源:https://stackoverflow.com/questions/11329955/rsacryptoserviceproviderrsacryptoserviceprovider-constructor-crashing-in-net

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!