C# 对于一个用户,从xml字符串导入DSA密钥失败。权限?坏的安装?坏的KSP?
一个用户最近报告说,在使用我的软件时出现了一个奇怪的错误。我使用DSA签名来验证许可证。当软件导入公钥以验证签名时,DSA提供程序的方法会抛出一个加密异常,描述为“密钥在指定状态下无法使用” 似乎从System.Security.Cryptography.Utils.CreateProvHandle调用的_OpenCSP方法返回NTE_BAD_KEY_状态(0x8009000b)。这是第一次有人向我报告这个错误,而且代码已经多年没有更改了 可能的原因是什么?屏蔽权限错误?损坏的CAPI装置?是否被.net信任/权限设置阻止?密钥存储提供程序存储的垃圾,或返回cryptoapi意外内容的KSP 我已经在谷歌上搜索了错误代码/描述/等等,但没有找到任何真正的答案来解释是什么导致了这一情况 失败代码的独立版本如下所示: 更新:在同一台计算机上运行.net fx 2.0时,相同的代码工作正常,但在.net fx 4.0下失败C# 对于一个用户,从xml字符串导入DSA密钥失败。权限?坏的安装?坏的KSP?,c#,.net,cryptography,cryptoapi,dsa,C#,.net,Cryptography,Cryptoapi,Dsa,一个用户最近报告说,在使用我的软件时出现了一个奇怪的错误。我使用DSA签名来验证许可证。当软件导入公钥以验证签名时,DSA提供程序的方法会抛出一个加密异常,描述为“密钥在指定状态下无法使用” 似乎从System.Security.Cryptography.Utils.CreateProvHandle调用的_OpenCSP方法返回NTE_BAD_KEY_状态(0x8009000b)。这是第一次有人向我报告这个错误,而且代码已经多年没有更改了 可能的原因是什么?屏蔽权限错误?损坏的CAPI装置?是否
更新2:DSA提供程序似乎会查找存储在%APPDATA%\Microsoft\Crypto\DSS\[SID]下的密钥,即使在使用现有密钥初始化时也是如此。这一机制是否存在冲突?任何人都知道密钥存储是如何工作的,以及从字符串加载公钥时为什么会被击中?您描述的问题似乎很有趣,但如果没有一些额外的信息和一些实验,很难确定原因是什么。所以我试着描述一下我是如何理解这个问题的 首先.NET加密类在内部使用非托管CryptoAPI。因此方法
\u OpenCSP
在内部调用函数。在其文档中,我们可以阅读以下有关错误的信息NTE\u BAD\u KEY\u STATE
(0x8009000BL):
用户密码已自更改
私钥被加密了
DSA提供程序使用的用户私钥保存为目录%APPDATA%\Microsoft\Crypto\DSS\[SID]
中的文件,并将使用相对复杂的算法进行加密,您可以从中读取。重要的是要了解目录中的文件对应于用户密钥的密钥容器。通常,用户可以完全访问文件系统中的文件。文件将使用依赖于用户密码的密钥进行加密。在许多标准情况下,文件在密码更改后将重新加密,但恢复算法取决于许多因素。如果密码被重置而不是由用户自己更改(由域管理员/帐户操作员等进行),则目录%APPDATA%\Microsoft\Crypto\DSS\[SID]
的旧包含可能不会更有用。例如,如果用户不是Active Directory用户(本地用户),并且本地管理员重置了其密码,则会出现加密容器问题
因此,第一个建议是询问用户是否重置了其Active Directory密码。接下来,您应该验证用户配置文件中是否存在目录%APPDATA%\Microsoft\Crypto\DSS\[SID]
,并且用户对文件系统中的目录具有完全访问权限。您应该从目录中删除所有文件(以前创建文件的备份副本)。顺便说一句,了解用户是否有中央保存的配置文件(保存在服务器上)很有趣。如果它具有中心配置文件,则可以验证用户的另一台计算机上是否存在您描述的相同问题,并且其他用户在其原始计算机上不会有问题
我不太清楚的另一个问题是为什么使用目录%APPDATA%\Microsoft\Crypto\DSS\[SID]
中的密钥容器,因为您只使用公钥。在CryptoAPI中,应使用CryptAcquireContext
和NULL
作为pszContainer
参数,并在dwFlags
中使用CRYPT\u VERIFYCONTEXT
。我不确定.NET是否使用了CRYPT\u VERIFYCONTEXT
标志,这可能会间接导致您的问题
您可以使用参数创建DSACryptoServiceProvider
。另一侧的属性在.NET 4.0中使用值进行扩展。csproviderflags.CreateEphemeralKey
的描述与CryptAcquireContext
函数的CRYPT\u VERIFYCONTEXT
标志的描述非常接近。所以use可以尝试使用或csproviderflags.CreateEphemeralKey
与csproviderflags.UseDefaultKeyContainer
(NULL
aspszContainer
的参数CryptAcquireContext
也表示默认密钥容器)
此外,如果可能的话,您可以尝试在可以重现问题的计算机上调试问题。要进行调试,您可以使用.NET源代码,这些源代码可以从中启用(请参阅和)或下载。然后,您可以回答有关当前程序中使用的CspParameters
值的一些问题,并比较.NET 3.5和.NET 4.0的值
如果我所写的内容无助于解决问题,请您在问题后面附加其他信息:
- 哪种操作系统和哪种service pack具有可以重现问题的计算机
- 问题是否取决于用户?我的意思是:同一台计算机上的其他用户也有同样的问题吗
- 域(active directory)用户或本地用户帐户是否存在问题?有问题的用户是否有保存在服务器上的中央用户配置文件?如果他有,那么p
using System; using System.Security.Cryptography; using System.Reflection; public class Test { public static void Main() { try { string key = "<DSAKeyValue><P>wrjxUnfKvH/1s5cbZ48vuhTjflRT5PjOFnr9GeUPZSIoZhYATYtME4JRKrXBtSkyioRNtE1xgghbGAyvAJ5jOWw88fLBF+P1ilsZyq72G1YcbB+co8ImQhAbWKmdCicO9/66Th2MB+7kms/oY3NaCzKEuR7J3b23dGrFpp4ccMM=</P><Q>xmxoSErIJCth91A3dSMjC6yQCu8=</Q><G>bwOLeEaoJHwSiC3i3qk9symlG/9kfzcgrkhRSWHqWhyPAfzqdV1KxJboMpeRoMoFr2+RqqKHgcdbzOypmTeN4QI/qh4nSsl5iEfVerarBOrFuRdOVcJO0d8WE233XQznd1K66nXa5L8d9SNZrM6umZ1YuBjhVsTFdPlIXKfGYhk=</G><Y>wZnEEdMUsF3U3NBQ8ebWHPOp37QRfiBn+7h5runN3YDee1e9bC7JbJf+Uq0eQmU8zDs+avEgD68NpxTKEHGr4nQ3rW6qqacj5SDbwO7nI6eN3wWrVhvrWcQm0tUO93m64HsEJREohfoL+LjqgrqIjZVT4D1KXE+k/iAb6WKAsIA=</Y><J>+zmcCCNm2kn1EXH9T45UcownEe7JH+gl3Lw2lhVzXuX/dYp5sGCA2lK119iQ+m3ogjOuwABATCVFLo6J66DsSlMd0I8WSD5WKPvypQ7QjY0Iv71J2N0FW0ZXpMlk/CE8zq4Z7arM1N564mNe</J><Seed>QDrZrUFowquY5Uay8YtUFOXnv28=</Seed><PgenCounter>Gg==</PgenCounter></DSAKeyValue>"; DSACryptoServiceProvider csp2 = new DSACryptoServiceProvider(); csp2.FromXmlString(key); Console.WriteLine("Success!"); } catch (Exception ex) { int hResult = 0; try { PropertyInfo pi = typeof(Exception).GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance); hResult = (int)pi.GetValue(ex, null); } catch (Exception ex2) { Console.WriteLine("HResult lookup failed: " + ex2.ToString()); } Console.WriteLine("Initializing CSP failed: " + ex.ToString() + "\r\nHResult: " + hResult.ToString("x")); } Console.WriteLine("\r\nPress Enter to continue"); Console.ReadLine(); } }
Initializing CSP failed: System.Security.Cryptography.CryptographicException: Ke y not valid for use in specified state. at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters paramete rs, Boolean randomKeyContainer) at System.Security.Cryptography.Utils.get_StaticDssProvHandle() at System.Security.Cryptography.DSACryptoServiceProvider.ImportParameters(DSA Parameters parameters) at System.Security.Cryptography.DSA.FromXmlString(String xmlString) at Test.Main() HResult: 8009000b
static string GenerateDsaKeyInDefaultContainer() { const int PROV_DSS_DH = 13; CspParameters cspParam = new CspParameters(PROV_DSS_DH); cspParam.KeyContainerName = null; cspParam.KeyNumber = (int)KeyNumber.Signature; cspParam.Flags = CspProviderFlags.UseDefaultKeyContainer; DSACryptoServiceProvider csp = new DSACryptoServiceProvider(cspParam); return csp.CspKeyContainerInfo.UniqueKeyContainerName; }