CryptographicException在试图导出X509私钥的RSAParameters时“密钥无法在指定状态下使用”

我盯着这一段时间,感谢MSDN文档,我无法弄清楚发生了什么事情。 基本上我是从光盘加载一个PFX文件到X509Certificate2并尝试使用公钥encryption一个string,并使用私钥解密。

为什么我感到困惑:当我将引用传递给RSACryptoServiceProvider本身时,encryption/解密工作:

 byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider); string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider); 

但是如果导出并传递RSAParameter

 byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false)); string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true)); 

…它会抛出一个“密钥在指定状态下无效”。 尝试将私钥导出到RSAParameterexception。 请注意PFX生成的证书被标记为可导出(即,我在创build证书时使用了pe标志)。 任何想法是什么导致例外?

  static void Main(string[] args) { X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test"); x.FriendlyName = "My test Cert"; X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); try { store.Add(x); } finally { store.Close(); } byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider); string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider); byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false)); string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true)); } private static byte[] EncryptRSA(string data, RSAParameters rsaParameters) { UnicodeEncoding bytConvertor = new UnicodeEncoding(); byte[] plainData = bytConvertor.GetBytes(data); RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider(); publicKey.ImportParameters(rsaParameters); return publicKey.Encrypt(plainData, true); } private static string DecryptRSA(byte[] data, RSAParameters rsaParameters) { UnicodeEncoding bytConvertor = new UnicodeEncoding(); RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider(); privateKey.ImportParameters(rsaParameters); byte[] deData = privateKey.Decrypt(data, true); return bytConvertor.GetString(deData); } private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey) { UnicodeEncoding bytConvertor = new UnicodeEncoding(); byte[] plainData = bytConvertor.GetBytes(data); return publicKey.Encrypt(plainData, true); } private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey) { UnicodeEncoding bytConvertor = new UnicodeEncoding(); byte[] deData = privateKey.Decrypt(data, true); return bytConvertor.GetString(deData); } 

只是为了澄清在上面的粗体部分是抛出: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);

我认为这个问题可能是关键没有标记为可导出的。 X509Certificate2还有另一个构造函数,它带有一个X509KeyStorageFlags枚举。 尝试更换该行:

 X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test"); 

有了这个:

 X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable); 

我遇到过类似的问题, X509KeyStorageFlags.Exportable解决了我的问题。

对于我遇到的问题,代码更改不是一个选项,因为相同的库已安装并在其他地方工作。

铱星的答案让我看起来可以导出密钥,我可以作为MMC证书导入向导的一部分。

希望这可以帮助别人。 感谢堆

证书导入向导

我不完全是这些东西的专家,但我做了一个快速的谷歌,并发现这一点:

http://social.msdn.microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce

“如果你的字节数组中有超过245个字节传递给你的RSACryptoServiceProvider.Encrypt(byte [] rgb,bool fOAEP)方法,那么它将抛出一个exception。

AFAIK这应该工作,你可能会碰到一个错误/一些限制。 这里有一些问题可以帮助你找出问题的出处。

  • 你是如何创buildPKCS#12(PFX)文件的? 我见过一些CryptoAPI不喜欢的密钥(非常见的RSA参数)。 你可以使用其他工具(只是为了确定)?

  • 你可以将PrivateKey实例导出到XML,例如ToXmlString(true) ,然后通过这种方式加载(导入)它?

  • 导入与当前实例不同大小的密钥(默认值为1024位)时,旧版本的框架存在一些问题。 你的证书中RSA公钥的大小是多less?

另外请注意,这不是你应该如何使用RSAencryption数据。 原始encryption的大小受限于正在使用的公钥。 循环这个限制只会给你真正糟糕的performance。

诀窍是使用完全随机密钥的对称algorithm(如AES ),然后使用RSA公钥对此密钥(wrap)进行encryption。 您可以在我的旧博客条目中find有关此主题的C#代码。

对于其他通过Google来到这里的人,但是不要使用任何X509Certificate2,如果你在RSACryptoServiceProvider上调用了ToXmlString,但是你只装载了一个公钥,那么你也会得到这个消息。 解决办法是这样的(注意最后一行):

 var rsaAlg = new RSACryptoServiceProvider(); rsaAlg.ImportParameters(rsaParameters); var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);