RSACryptoServiceProvider加密提供程序在ASP.NET下出现CryptographicException“系统找不到指定的文件”。

18
我有一个应用程序,正在使用RSACryptoServiceProvider来解密一些数据,使用已知的私钥(存储在变量中)。
当IIS应用程序池配置为使用Network Service时,一切都运行良好。
然而,当我们将IIS应用程序池配置为在不同的身份下运行代码时,我们会遇到以下问题:
System.Security.Cryptography.CryptographicException:系统找不到指定的文件。
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer) at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters) at System.Security.Cryptography.RSA.FromXmlString(String xmlString)
代码类似于这样:
byte[] input; 
byte[] output; 
string private_key_xml; 

var provider = new System.Cryptography.RSACryptoServiceProvider(this.m_key.Key_Size);
provider.FromXmlString(private_key_xml); // Fails Here when Application Pool Identity != Network Service

ouput = provider.Decrypt(input, false); // False = Use PKCS#1 v1.5 Padding

有一些资源试图通过声明你应该给用户读取机器密钥存储的访问权限来回答这个问题,但是没有确定性的解决方案可以解决这个问题。

环境:IIS 6.0,Windows Server 2003 R2,.NET 3.5 SP1

5个回答

39

这是因为密钥存储在DPAPI中 http://security.stackexchange.com/q/1771/396 - makerofthings7
谢谢,这在服务器上对我有用,但在本地不行,我想知道为什么。 我读到这个函数尝试访问密钥库并因权限而失败,即使代码不需要使用密钥库。 - Ronen Festinger
好的,我找到了为什么它在我的机器上不起作用的原因。这是因为我使用了一个应用程序池,该应用程序池已经被其他应用程序使用过了。我不太确定为什么会引起问题,但当我设置了一个专用的应用程序池时,它就可以工作了! - Ronen Festinger
谢谢!我只在生产环境中遇到了这个问题,现在已经解决了。 - Jeff
有人知道为什么它能工作吗?它在2008年可以工作,但在2012年就停止了。@Tim说它应该在2008年就停止工作了。 - Mike

13

确实,你需要像这样编写代码

CspParameters _cpsParameter;
RSACryptoServiceProvider RSAProvider;

_cpsParameter = new CspParameters();
_cpsParameter.Flags = CspProviderFlags.UseMachineKeyStore;

RSAProvider = new RSACryptoServiceProvider(1024, _cpsParameter); 
以下用户需要访问文件夹:C:\Documents and Settings\All Users\Application data\Microsoft\Crypto\RSA\MachineKeys

  1. IIS用户帐户(匿名)
  2. 您在web.config设置中模拟应用程序使用的用户帐户。

所以现在它对我来说运行良好。


谢谢你的回答 - 我还没有机会实际测试这个。你知道新账户默认情况下(干净的Windows安装)是否已经有访问权限了吗?我们正在尝试避免修改太多 - 这似乎是一个特别奇怪的问题,因为它应该在低/中信任下运行。 - user111013
威尔,我不确定!这个特定的问题只发生在我的机器上。我已经在另一台开发者的机器上尝试过,事情按照预期工作。在服务器上,我们的系统运行在不同的用户上下文中,所以我也没有问题。 - Eduardo Xavier

8

尝试设置

System.Security.Cryptography.RSACryptoServiceProvider.UseMachineKeyStore = true;

编辑: 那么尝试使用

var provider = new System.Security.Cryptography.RSACryptoServiceProvider();

使用不带整数参数的构造函数代替。该构造函数尝试生成指定密钥长度的密钥,但您可能无法使用您的权限执行此操作。


这对我在具有默认apppool身份的IIS7上运行成功。 - Mike Hadlow
2
如果您不想全局启用标志,似乎您也可以调用“new RSACryptoServiceProvider(new CspParameters {Flags = CspProviderFlags.UseMachineKeyStore})”。 - Ben Challenor
这也解决了我在实例化RSACryptoServiceProvider时遇到的“访问被拒绝”错误。 - Kwaak

2

我只是想评论一下Rasmus Faber的解决方案对我有效(只需进行一次小修改):

System.Cryptography.RSACryptoServiceProvider.UseMachineKeyStore = true;
RSACryptoServiceProvider provider = new System.Cryptography.RSACryptoServiceProvider();

我试图使用DKIM让MailBee.net签署发件人消息,但是收到了与OP相同的错误消息。当然,在我的开发机上一切都很好,但是当我上传到客户的Web主机时,遇到了这个问题。就像我说的,上面的解决方案对我有用,而我在网上找到的其他解决方案(包括上面的msdn论坛链接)则没有用。

(我想点赞和评论,但我没有足够的声望:P)

谢谢Rasmus Faber!


0

只有当我添加了

Flags = CspProviderFlags.UseMachineKeyStore

问题就解决了。

{
    string keyName = "Secret***";
    CspParameters parameters = new CspParameters()
    {
        KeyContainerName = keyName,
        Flags = CspProviderFlags.UseMachineKeyStore
    };
}

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