C# “加密例外”;密钥在指定状态下无效。”;尝试导出X509私钥的参数时
我盯着这个看了很长一段时间,多亏了这个,我真的不知道发生了什么。基本上,我正在将一个PFX文件从光盘加载到C# “加密例外”;密钥在指定状态下无效。”;尝试导出X509私钥的参数时,c#,.net,encryption,cryptography,rsa,C#,.net,Encryption,Cryptography,Rsa,我盯着这个看了很长一段时间,多亏了这个,我真的不知道发生了什么。基本上,我正在将一个PFX文件从光盘加载到X509Certificate2中,并尝试使用公钥加密字符串,使用私钥解密 为什么我感到困惑:当我将引用传递给rsacyptoserviceprovider本身时,加密/解密工作正常: byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider); string foo1 = De
X509Certificate2
中,并尝试使用公钥加密字符串,使用私钥解密
为什么我感到困惑:当我将引用传递给rsacyptoserviceprovider
本身时,加密/解密工作正常:
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));
…它在尝试将私钥导出到rsapameter
时引发“密钥在指定状态下无效”异常。请注意,生成PFX的证书标记为可导出(即,我在创建证书时使用了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=decryptsa(ed,(x.PrivateKey作为rsacyptoserviceprovider)**.ExportParameters(true)**)代码>我不是这些方面的专家,但我在谷歌上快速搜索了一下,发现:
“如果传递给RSACryptServiceProvider.Encrypt(byte[]rgb,bool fOAEP)方法的字节数组中有超过245个字节,则该方法将引发异常。”AFAIK这应该是可行的,并且您可能遇到错误/某些限制。下面的一些问题可能会帮助您找出问题所在
- 您是如何创建PKCS#12(PFX)文件的?我见过一些CryptoAPI不喜欢的密钥(不常见的RSA参数)。你能用另一个工具吗(只是为了确定)
- 能否将
PrivateKey
实例导出为XML,例如ToXmlString(true)
,然后以这种方式加载(导入)它
- 旧版本的框架在导入与当前实例大小不同(默认为1024位)的密钥时出现一些问题。证书中RSA公钥的大小是多少
还请注意,这不是使用RSA加密数据的方式。原始加密的大小受所用公钥的限制。循环超过此限制只会给您带来非常糟糕的性能
诀窍是使用对称算法(如AES)和完全随机密钥,然后使用RSA公钥加密该密钥(wrap)。你可以在我的旧版本中找到C#代码来实现这一点。我认为问题可能在于密钥没有标记为可导出。X509Certificate2
还有另一个构造函数,它接受X509KeyStrageFlags枚举。尝试替换该行:
X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test");
为此:
X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable);
我遇到了一些类似的问题,X509keystrageFlags.Exportable
解决了我的问题。对于其他通过Google到达这里但不使用任何X509Certificate2的用户,如果您在RSACryptServiceProvider上调用ToXmlString,但只加载了公钥,您也会收到此消息。解决方法如下(注意最后一行):
对于我遇到的问题,代码更改不是一个选项,因为相同的库已安装并在其他地方工作
Iridium的回答让我看到了如何使密钥可导出,我能够将其作为MMC证书导入向导的一部分
希望这对其他人有帮助。谢谢你
这是一篇老文章,但也许可以帮助别人。
如果您使用的是自签名证书并使用其他用户登录,则必须从存储器中删除旧证书,然后重新创建它。我在opc ua软件方面也遇到了同样的问题如果我没有很好地说明我自己,我可以打断这行:string foo=DecryptRSA(ed,(x.PrivateKey作为rsacyptoserviceprovider)。ExportParameters(true));into:var pvk=(x.PrivateKey作为RSACryptoServiceProvider);var pvkParam=pvk.ExportParameters(true);字符串foo=已解密RSA(已加密,pvkParam)。。。如果我这样做pvk.ExportParameters(true);将抛出。此错误是有史以来最烦人的错误之一。它可能意味着很多事情。对我来说,正如Jeroen所说:我的消息文本太大,无法用密钥加密(这是异步加密的缺点)。谢谢!你给我省了很多麻烦!:)8年后,这救了我的疯狂!发自内心的感谢。设置此可导出标志的负面影响/陷阱是什么?@ElFik-由于私钥用于解密和签名,因此确保其安全非常重要。设置Exportable标志后,私钥可以保存到文件中并复制到其他位置。如果您希望能够将密钥复制到另一台机器等,这一点很好,但确实会降低安全性,因为私钥也可以更容易地被未经授权的第三方提取(例如,如果您让电脑登录并解锁)。这并不是说在未设置Exportable标志的情况下,无法提取密钥,但这肯定会使提取变得更加困难。明白了,因此该指南可以概括为“仅在需要时使用Exportable,但如果需要,请随意使用”?在德语中,错误消息为“Schlüssel的状态不正确。
”。
var rsaAlg = new RSACryptoServiceProvider();
rsaAlg.ImportParameters(rsaParameters);
var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);