C# CryptographicException "密钥在指定状态下无效。" 在尝试导出 X509 私钥的 RSAParameters 时

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9358129/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 07:01:11  来源:igfitidea点击:

CryptographicException "Key not valid for use in specified state." while trying to export RSAParameters of a X509 private key

c#.netencryptioncryptographyrsa

提问by kalrashi

I am staring at this for quite a while and thanks to the MSDN documentationI cannot really figure out what's going. Basically I am loading a PFX file from the disc into a X509Certificate2and trying to encrypt a string using the public key and decrypt using the private key.

我盯着这个看了很长时间,多亏了MSDN 文档,我无法真正弄清楚发生了什么。基本上,我将 PFX 文件从光盘加载到 a 中,X509Certificate2并尝试使用公钥加密字符串并使用私钥解密。

Why am I puzzled: the encryption/decryption works when I pass the reference to the RSACryptoServiceProvideritself:

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

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

But if the export and pass around the RSAParameter:

但是如果导出并传递RSAParameter

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

...it throws a "Key not valid for use in specified state." exception while trying to export the private key to RSAParameter. Please note that the cert the PFX is generated from is marked exportable (i.e. I used the pe flag while creating the cert). Any idea what is causing the exception?

...它抛出“密钥在指定状态下无效。” 尝试将私钥导出到RSAParameter. 请注意,生成 PFX 的证书被标记为可导出(即我在创建证书时使用了 pe 标志)。知道是什么导致了异常?

 static void Main(string[] args)
    {
        X509Certificate2 x = new X509Certificate2(@"C:\temp\certs\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);
}

Just to clarify in the code above the bold part is throwing: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);

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

回答by Jeroen Jacobs

I'm not exactly an expert in these things, but I did a quick google, and found this:

我不是这些方面的专家,但我做了一个快速的谷歌,发现了这个:

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

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

"if you have more than 245 bytes in your byte array that you pass to your RSACryptoServiceProvider.Encrypt(byte[] rgb, bool fOAEP) method then it will throw an exception."

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

回答by poupou

AFAIK this should work and you're likely hitting a bug/some limitations. Here's some questions that may help you figure out where's the issue.

AFAIK 这应该可行,您可能会遇到错误/某些限制。这里有一些问题可以帮助您找出问题所在。

  • How did you create the PKCS#12 (PFX) file ? I've seen some keys that CryptoAPI does not like (uncommon RSA parameters). Can you use another tool (just to be sure) ?

  • Can you export the PrivateKeyinstance to XML, e.g. ToXmlString(true), then load (import) it back this way ?

  • Old versions of the framework had some issues when importing a key that was a different size than the current instance (default to 1024 bits). What's the size of your RSA public key in your certificate ?

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

  • 您可以将PrivateKey实例导出到 XML,例如ToXmlString(true),然后以这种方式加载(导入)回来吗?

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

Also note that this is nothow you should encrypt data using RSA. The size of the raw encryption is limited wrt the public key being used. Looping over this limit would only give you reallybad performance.

另请注意,这不是您应该使用 RSA 加密数据的方式。原始加密的大小受到使用的公钥的限制。循环超过这个限制只会给你带来非常糟糕的性能。

The trick is to use a symmetric algorithm (like AES) with a totallyrandom key and then encrypt this key (wrap) using the RSA public key. You can find C# code to do so in my old blog entryon the subject.

诀窍是使用具有完全随机密钥的对称算法(如AES),然后使用 RSA 公钥加密此密钥(包装)。您可以在我关于该主题的旧博客条目中找到 C# 代码。

回答by Iridium

I believe that the issue may be that the key is not marked as exportable. There is another constructor for X509Certificate2that takes an X509KeyStorageFlags enum. Try replacing the line:

我认为问题可能在于密钥未标记为可导出。还有另一个构造函数X509Certificate2需要一个 X509KeyStorageFlags 枚举。尝试替换该行:

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

With this:

有了这个:

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

回答by user1187372

I've met some similar issue, and X509KeyStorageFlags.Exportablesolved my problem.

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

回答by Gijs

For others that end up here through Google, but don't use any X509Certificate2, if you call ToXmlString on RSACryptoServiceProvider but you've only loaded a public key, you will get this message as well. The fix is this (note the last line):

对于通过 Google 到达此处但不使用任何 X509Certificate2 的其他人,如果您在 RSACryptoServiceProvider 上调用 ToXmlString 但您只加载了公钥,您也会收到此消息。修复是这样的(注意最后一行):

var rsaAlg = new RSACryptoServiceProvider();

rsaAlg.ImportParameters(rsaParameters);

var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);

回答by will webster

For the issue I encountered a code change was not an option as the same library was installed and working elsewhere.

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

Iridium's answer lead me to look making the key exportable and I was able to this as part of the MMC Certificate Import Wizard.

Iridium 的回答让我考虑使密钥可导出,并且我能够将其作为 MMC 证书导入向导的一部分。

Hope this helps someone else. Thanks heaps

希望这对其他人有帮助。谢谢堆

Cert import wizard

证书导入向导

回答by Flavio Bianchi

Old post, but maybe can help someone. If you are using a self signed certificate and make the login with a different user, you have to delete the old certificate from storage and then recreate it. I've had the same issue with opc ua software

旧帖子,但也许可以帮助某人。如果您使用自签名证书并使用其他用户登录,则必须从存储中删除旧证书,然后重新创建它。我在 opc ua 软件上遇到了同样的问题