系统安全加密异常:密钥集不存在。

67

我使用 x509 证书加密和解密消息时,出现了一些错误信息,并且无法解决这个问题。是否有人遇到过并解决了这个错误?谢谢。

描述:在当前 Web 请求的执行期间发生了未处理的异常。请查看堆栈跟踪以获取有关该错误的更多信息以及代码中它的来源。

异常详细信息:

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

源错误:

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

源文件:E:\PayUSite\PayMvcApp\Controllers\HashMessageController.cs 行号:55

堆栈跟踪:

[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

源代码:

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

可能是加密异常“Keyset不存在”,但仅通过WCF的重复问题。 - WhiteKnight
1
我以前见过这种情况。在Cryptographic Interoperability: Digital Signatures中搜索“Keyset does not exist”。我认为有几个句柄是打开的。当它们被垃圾回收时,共享资源会被清理多次(这是不起作用的)。我会仔细查看certEncrypt.PrivateKey(加密通常使用公钥)和cerDecrypt.PublicKey(解密通常使用私钥)。我认为它们在离开using块时被清理了。 - jww
10个回答

152

虽然这个问题很老了,但是对于那些仍在使用 EncryptDecrypt 的人来说,以下是我解决此错误的方法:

我的证书安装方式不正确,是通过双击 .pfx 文件并选择存储方式安装的。

错误的证书安装方式

1. 双击证书:

certificate file

2. 向导弹出,点击下一步按钮:

wizard 0

3. 向导显示证书位置,点击下一步按钮:

wizard 1

4. 输入密码然后点击下一步:

wizard 2

5. 选择存储位置然后点击下一步:

wizard 3

6. 向导显示证书信息,点击完成按钮

wizard 4

7. 成功对话框显示:

wizard 5

此时,我遇到了错误"Keyset does not exist"


正确的解决方法如下

1. 执行Microsoft Management Console(mmc.exe):

execute mmc

2. 一个空的MMC实例显示:

mmc showed

3. 点击文件->添加/删除管理单元...

add snap-in

4. 选择证书管理单元并单击添加按钮:

add certificate snap-in

5. 选择 计算机帐户 然后单击下一步按钮:

select computer account

6. 选择 本地计算机 然后单击完成按钮:

selecct local computer

7. 现在已经添加了证书管理单元,单击确定按钮:

certificate snap-in shows

8. 选择个人存储,然后右键单击并选择导入

select personal store and import

9. 浏览证书,然后单击下一步:

browse certificate

10. 输入密码,然后单击下一步按钮:

enter image description here

11. 自动选择证书存储:

自动选择商店

12. 证书信息如下:

证书信息

13. 成功的对话框消息如下:

输入图像说明

14. 刷新MMConsole以显示证书:

刷新mmc

15. 右键单击证书,然后单击管理私钥...:

管理私钥

16. 将池标识或IIS用户添加到我的情况下,我添加了IIS_IUSRS:

添加iis_iusrs

17. 用户已添加,请单击确定按钮:

用户已添加

现在,密钥集已经存在!!


39
如果您说“用户没有私钥权限,所以需要授予权限”,您的回答就可以更简单明了。解决方法与如何导入证书无关(没有“正确”或“错误”的导入方式)。感谢您提供的最后一步解决方案! - stefann
8
我也遇到了这个问题,设置证书权限正是问题所在!感谢你提供的出色答案,截图真是太赞了! - Philip Pittle
3
通常这是一个权限问题。您需要授予应用程序/服务正在运行的用户帐户读取权限。 - Snives
3
在我的情况下,通过MMC控制台安装证书是有效的。但是双击 .PFX 文件安装则无效。 - aledpardo
3
第15和16项条款很重要。 - WorkInProgress
显示剩余5条评论

13

我收到了与OP相同的错误信息:

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

解决方法(适用于我)是: 需要以管理员身份运行Visual Studio。

正如别人(可能不适用于所有情况)所解释的那样,必须以管理员身份运行VS,才能从密钥存储中提取证书的私钥,以便与密钥保险库进行身份验证/握手。


1
@PalleDue,你的应用程序不需要以管理员身份运行,只需在已经被授权使用证书的用户/服务帐户凭据下运行即可,否则你可能需要重新考虑你的应用程序认证架构。如果证书安装位置允许,在不以管理员身份运行VS的情况下,通过对证书进行认证也可以解决这个问题。 - bryan.hunwardsen

11

我也遇到了同样的问题。这个提示信息不太理想,而在我的情况中,我的用户没有权限访问私钥。您可以通过以下步骤解决此问题:

  1. 打开mmc
  2. 添加证书管理控制台
  3. 选择要使用的证书
  4. 右键单击它并选择“所有任务” /“管理私钥...”
  5. 将您的用户添加到授权用户列表中,并允许“完全控制”

8

尝试以管理员身份运行VS。这对我有用。


8
应用可能尝试写入以下文件夹路径:C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys。
如果您的应用使用模拟用户或使用IUSR_MACHINENAME用户,则配置MachineKeys文件夹安全性并授予用户读取和执行、列出文件夹内容、读取、写入权限。如果这样不起作用,尝试给"Everyone"用户相同的权限。

我尝试将“everyone”用户组的写入权限赋予MachineKeys目录,但仍然显示相同的错误信息。 - Bes Ley
我的理解是,上面提到的MachineKeys文件夹之所以具有受限权限,是因为它应该在操作系统的控制下。你不应该直接访问它。 - Stephen G Tuggy

4
我认为在使用加密和解密时,需要使用公钥进行加密和私钥进行解密。因此,如果您尝试在没有私钥的情况下解密,就会导致异常。 您应该真正使用SignData方法创建签名,并使用VerifyData进行验证。

有太多的接收者,最好的方法是发送方提供公钥(给接收者)和私钥(给自己)。 - Bes Ley
你是正确的,我修改了我的代码使用CreateSignature而不是encrypt,现在可以运行并得到正确的结果。谢谢 :-) - Bes Ley

1
我在尝试对SAML响应进行签名时,由于没有将证书中的PrivateKey加载到signedXmlElement的SigningKey中,导致出现了这个错误。
signedElement.SigningKey = myCertificate.PrivateKey;

1

.Net在这里创建临时证书文件 "..\Microsoft\Crypto\RSA\MachineKeys"。 可能证书文件仍被其他进程锁定。尝试重启应用程序和计算机。如果问题得到解决,则需要手动创建 .pfx 文件,然后将证书加载到您的计算机上的应用程序中。


请在您的回答中提供更多细节。目前的写法让人难以理解您的解决方案。 - Community
如果您有新的问题,请通过单击提问按钮来提出。如果它有助于提供上下文,请包含此问题的链接。 - Emmanuel Ponnudurai

0
在我的情况下,私钥存储在"C:\ProgramData\Microsoft\Crypto\Keys"而不是machinekeys文件夹中 - 您可以使用certutil检查“唯一容器名称”以找到私钥。
现在,我浏览加密目录以找到匹配项。有了这个匹配项,我就可以在适当的文件上设置正确的ACL。

0

如果你在从Visual Studio运行代码时遇到了这个问题,那么以管理员身份运行Visual Studio将解决问题;如果你在将代码发布到IIS后遇到了这个问题,则按照以下步骤解决:

1. 打开IIS并右键单击API/网站,选择“管理应用程序” => “高级设置”,查找正在使用的应用程序池

enter image description here

enter image description here

2. 点击应用程序池

enter image description here

3. 在您的 API 使用的应用程序池上单击右键,然后选择“高级设置”

enter image description here

4. 将“Identity”更改为“本地系统”,然后按下“确定”按钮

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接