CryptographicException"密钥无法在指定状态下使用." 在尝试导出X509私钥的RSAParameters时

kal*_*shi 52 .net c# encryption cryptography rsa

我盯着这看了很长一段时间,感谢MSDN文档我无法弄清楚到底发生了什么.基本上我正在将光盘中的PF​​X文件加载到a中,X509Certificate2并尝试使用公钥加密字符串并使用私钥解密.

为什么我感到困惑:加密/解密在我将引用传递给RSACryptoServiceProvider自身时起作用:

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

但如果出口和传递RSAParameter:

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

...它会抛出"密钥无法在指定状态下使用".尝试将私钥导出到的异常RSAParameter.请注意,生成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);
}
Run Code Online (Sandbox Code Playgroud)

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

Iri*_*ium 115

我认为问题可能是密钥没有标记为可导出.还有另一个构造函数X509Certificate2需要一个X509KeyStorageFlags枚举.尝试更换该行:

X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\1\test.pfx", "test");
Run Code Online (Sandbox Code Playgroud)

有了这个:

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

  • 谢谢!你救了我一大堆麻烦!:) (7认同)
  • 8年后,这拯救了我的疯狂!我从心底里感谢你。 (2认同)
  • @ElFik - 由于私钥用于解密和签名,因此保持其安全非常重要。当设置可导出标志时,私钥可以保存到文件中并复制到其他地方,虽然如果您希望能够将密钥复制到另一台机器等,这很好,但它确实会在一定程度上降低安全性,因为它也可以更容易地被未经授权的第三方提取(例如,如果您让您的电脑保持登录状态并解锁)。这并不是说在“未设置”可导出标志的情况下“不可能”提取密钥,但这肯定会使提取变得更加困难。 (2认同)

小智 13

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

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

希望这有助于其他人.谢谢堆

证书导入向导


use*_*372 9

我遇到了一些类似的问题,并X509KeyStorageFlags.Exportable解决了我的问题.


Jer*_*obs 3

我不完全是这些事情的专家,但我快速谷歌了一下,发现了这个:

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

“如果传递给 RSACryptoServiceProvider.Encrypt(byte[] rgb, bool fOAEP) 方法的字节数组中的字节数超过 245 个字节,那么它将引发异常。”