63

When I make an x509 certificate to encrypt and decrypt messages, I got some error information and could not able to fix this problem. Could someone ever happen to solve this bug? thanks.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details:

System.Security.Cryptography.CryptographicException: keyset does not exist。

Source Error:

Line 53: using (RSACryptoServiceProvider rsaProviderDecrypt = (RSACryptoServiceProvider)cerDecrypt.PublicKey.Key) Line 54:
{ Line 55: plainHashBytes = rsaProviderDecrypt.Decrypt(encryptedHashBytes, false); Line 56:
rsaProviderDecrypt.Clear(); Line 57:
rsaProviderDecrypt.Dispose();

Source File: E:\PayUSite\PayMvcApp\Controllers\HashMessageController.cs Line: 55

Stack Trace:

[CryptographicException: keyset does not exist. ]
System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +41
System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey) +0
System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP) +579

source code:

string docFile = Server.MapPath("~/docx/DirectAccess_StepByStep.doc");
HashAlgorithm hash = HashAlgorithm.Create("SHA1");
byte[] hashedBytes;
using (FileStream fs = new FileStream(docFile, FileMode.Open))
{
    //compute message hash value
    hashedBytes = hash.ComputeHash(fs);
    hash.Dispose();
    fs.Close();
}
    
string hashedString = Convert.ToBase64String(hashedBytes);
    
//encrypt message digest
string priKeyFile = Server.MapPath("~/certificate/WosMiddle.pfx");
X509Certificate2 certEncrypt = new X509Certificate2(priKeyFile, "123456");
byte[] encryptedHashBytes;
using (RSACryptoServiceProvider rsaProviderEncrypt = (RSACryptoServiceProvider)certEncrypt.PrivateKey)
{
    encryptedHashBytes = rsaProviderEncrypt.Encrypt(hashedBytes, false);
    rsaProviderEncrypt.Dispose();
}
    
//decrypt message digest
string pubKeyFile = Server.MapPath("~/certificate/WosMiddle-pubkey.cer");
X509Certificate2 cerDecrypt = new X509Certificate2(pubKeyFile);
byte[] plainHashBytes;
using (RSACryptoServiceProvider rsaProviderDecrypt = (RSACryptoServiceProvider)cerDecrypt.PublicKey.Key)
{
    //***will throw error message here...***
    plainHashBytes = rsaProviderDecrypt.Decrypt(encryptedHashBytes, false);
    rsaProviderDecrypt.Dispose();
}
    
//verify message whether was modified
string docFile2 = Server.MapPath("~/docx/DirectAccess_StepByStep.doc");
HashAlgorithm hash2 = HashAlgorithm.Create("SHA1");
byte[] hashedBytes2;
using (FileStream fs2 = new FileStream(docFile2, FileMode.Open))
{
    //compute message hash value
    hashedBytes2 = hash.ComputeHash(fs2);
    fs2.Close();
}
    
//compare hash value
bool isEqual = plainHashBytes.SequenceEqual(hashedBytes2);
Mihir Ajmera
  • 127
  • 1
  • 9
Bes Ley
  • 1,685
  • 1
  • 20
  • 39
  • possible duplicate of [CryptographicException 'Keyset does not exist', but only through WCF](http://stackoverflow.com/questions/602345/cryptographicexception-keyset-does-not-exist-but-only-through-wcf) – WhiteKnight Aug 22 '14 at 09:54
  • 1
    I've seen this happen before. Search for "Keyset does not exist" at [Cryptographic Interoperability: Digital Signatures](http://www.codeproject.com/Articles/25590/Cryptographic-Interoperability-Digital-Signatures). I *think* there are a couple of handles open. When they are garbage collected, the shared resource is cleaned up multiple times (which does not work). I'd look closely at `certEncrypt.PrivateKey` (encrypt usually uses public keys) and `cerDecrypt.PublicKey` (decrypt usually uses private keys). I think they are cleaned up when leaving the `using` block. – jww Aug 22 '14 at 10:52

10 Answers10

149

This question is old but for someone looking for the solution while continuing to use Encrypt and Decrypt here is how I manage to solve this error:

The base is my certificate have been installed the wrong way by double-clicking the .pfx file and selecting the store.

The wrong way to install the certificate

1. Double click the certificate:

certificate file

2. The wizard opens, click in the next button:

wizard 0

3. The wizard show the certificates location, click in the next button:

wizard 1

4. Enter the password then click next:

wizard 2

5. Select the store then click next:

wizard 3

6. The wizard show the certificate information, click in Finish button

wizard 4

7. Succes dialog is showed:

wizard 5

So at this point I had the error "Keyset does not exist".


To solve that I proceeded this way (the correct way)

1. Execute Microsoft Management Console (mmc.exe):

execute mmc

2. A blank MMC instance showed:

mmc showed

3. Click in File->Add/Remove Snap-in...

add snap-in

4. Select certificate snap-in an click in Add button:

add certificate snap-in

5. Select Computer account then click in Next button:

select computer account

6. Select Local computer then click in Finish button:

selecct local computer

7. The certificate snap-in is now added, click in OK button:

certificate snap-in shows

8. Select the personal store, then right click and select Import:

select personal store and import

9. Browse the certificate, and click next:

browse certificate

10. Enter the password, then click in Next button:

enter image description here

11. Automatically select the certificate store:

automatically select the store

12. The certificate information shows:

certificate information

13. Success dialog message shows:

enter image description here

14. Refresh the MMConsole to show the certificate:

refresh mmc

15. Right click on the certificate, then click in Manage Private Keys...:

manage private keys

16. Add the pool identity or the IIS user in my case I added IIS_IUSRS:

add iis_iusrs

17. The user has been added, click on OK button:

user added

And it is finished the keyset does exist now!!

sabotero
  • 4,265
  • 3
  • 28
  • 43
  • 38
    You could have simplified your answer a great deal by saying "user doesn't have permissions to the private key so you need to give it permissions". The solution is independent of how you import the certificate (there isn't a "right" or "wrong" way to import). Thanks for the last step in the solution though! – stefann Oct 25 '14 at 02:15
  • Actually in some version of windows it does matter the way you import. – sabotero Oct 27 '14 at 08:19
  • 8
    I had this problem too and setting the certificate permissions was exactly the issue! Thanks for the excellent answer; screenshots ftw! – Philip Pittle May 05 '15 at 19:26
  • 3
    This is usually a permissions issue. You need to grant read permissions to the user account that the application/service is running under. – Snives Jun 01 '15 at 21:41
  • 3
    In my case, installing the certificate from the MMC console worked. Installing by double-clicking the .PFX didn't. – aledpardo Apr 05 '16 at 17:27
  • 1
    If you need to give IIS webapp permission for one app pool such as DefaultAppPool, you can use username: IIS APPPOOL\DefaultAppPool for the ApplicationsPoolIdentity username. – Dan Randolph May 16 '17 at 18:27
  • 3
    Line item 15 and 16 are important ones. – WorkInProgress Sep 21 '17 at 13:36
  • In windows 10 I had to use \IIS_IUSRS – Rich Jun 29 '18 at 15:50
  • 1
    Also try running VS as Administrator. That fixed it for me – Bhavesh Aug 23 '19 at 06:31
  • One thing to note is that to have access to the option "Manage Private Keys..." in step 15 in Windows Server is that you have to import a **.PFX** and not a **.CER** file. And the certificate must be located in the **Personal folder** in MMC, if you put the certificate in another folder the option won't be shown. – vcRobe Aug 30 '19 at 15:05
13

I received same error as OP: "System.Security.Cryptography.CryptographicException: keyset does not exist"

The resolution (for me) was: Visual Studio needs to be (run as Admin)

As was explained to me(YMMV), VS needs to be run as Admin in order to extract the certificates private key from the key store, in order to negotiate auth/handshake with keyvault.

  • 1
    @PalleDue, your application does not need to run as admin, it just has to be run under a user/service account credential that has been authorized on the certificate, else you may need to re-think your apps auth architecture. This solution may also work if you auth yourself to the cert without running VS as admin depending on where the cert is installed. – bryan.hunwardsen Jul 14 '20 at 18:06
10

I did run into the same problem. The message is not ideal and in my case my user did not have permission to access the private key. You can fix this using these steps:

  1. Open mmc
  2. Add certificate snap-in
  3. select the certificate you want to use
  4. right click on it and select 'All Tasks' / 'Manage Private Keys...'
  5. Add your user to the list of authorized users and allow 'Full Control'
Johnny Graber
  • 1,427
  • 5
  • 27
  • 33
8

The application might be trying to write to the following folder path: C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys

If your application is using impersonation or using the IUSR_MACHINENAME user, then configure the MachineKeys folder sercurities and give the user Read & Execute, List Folder Contents, Read, Write. If that doesn't work, try giving the Everyone user the same permissions.

eMi
  • 5,540
  • 10
  • 60
  • 109
  • I have tried to make write permission to the MachineKeys directory for "everyone", but it still showed the same error message. – Bes Ley Aug 28 '12 at 08:23
  • My understanding is that the MachineKeys folder referenced above has restricted permissions for a good reason: It's supposed to be under the control of the operating system. You aren't supposed to be able to access it directly. – Stephen G Tuggy Feb 08 '17 at 21:47
8

Try running vs as Administrator. Worked for me

Bhavesh
  • 819
  • 1
  • 17
  • 31
4

I believe when using Encrypt and Decrypt it expects a public key for encrypt and a private key for decrypt. So it is failing because you are trying to decrypt without the private key and that causes the exception.

You should really be using SignData method for creating the signature and VerifyData for the verification.

tyranid
  • 13,028
  • 1
  • 32
  • 34
  • There are too many recievers and it's better that the sender provides public key(for recievers) and private key(for himself or herself). – Bes Ley Aug 28 '12 at 08:08
  • You are right, I modified my code to use CreateSignature instead of encrypt, and that could run and make correct result. thanks.:-) – Bes Ley Aug 31 '12 at 07:25
1

I ran into this error when I wasn't loading in the PrivateKey from my certificate into my signedXmlElement's SigningKey when trying to sign a SAML response.

signedElement.SigningKey = myCertificate.PrivateKey;
Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
Mough
  • 56
  • 4
1

.Net create temp certificate file here "..\Microsoft\Crypto\RSA\MachineKeys". May be the certificate file still locked an other process. Try restart app then pc. If the problem solved, you need to create manuelly .pfx file then load certificate app your pc.

  • Please provide additional details in your answer. As it's currently written, it's hard to understand your solution. – Community Aug 31 '21 at 12:39
  • If you have a new question, please ask it by clicking the [Ask Question](https://stackoverflow.com/questions/ask) button. Include a link to this question if it helps provide context. – Emmanuel Ponnudurai Sep 04 '21 at 04:20
0

In my case the private key was stored in "C:\ProgramData\Microsoft\Crypto\Keys" and not machinekeys folder - you can check using certutil to find out the "Unique container name" that will be the private key.

I now scan through the crypto directory to find the match. WIth that match I can set the correct ACL on the appropriate file

Dai Bok
  • 3,451
  • 2
  • 53
  • 70
0

If you are facing this issue while running code from visual studio then running visual studio as administrator will solve the probelm or if you are facing this issue after publishing on IIS then following steps will solve the problem:

1. Open IIS and Right click on API/website and click Manage Application => Advanced Settings to find which application pool is being used

enter image description here

enter image description here

2. Click Application Pool

enter image description here

3. Right click on the Application Pool used by your API and then select "Advanced Settings"

enter image description here

4. Change "Identity" to "Local System" and press Ok button

enter image description here

S.ATTA.M
  • 409
  • 5
  • 10