it-swarm.com.de

CryptographicException "Schlüssel ist für den angegebenen Status nicht gültig." beim Versuch, RSAParameter eines privaten X509-Schlüssels zu exportieren

Ich starre schon eine ganze Weile darauf und dank der MSDN-Dokumentation kann ich nicht wirklich herausfinden, was los ist. Grundsätzlich lade ich eine PFX-Datei von der Disc in einen X509Certificate2 Und versuche, einen String mit dem öffentlichen Schlüssel zu verschlüsseln und mit dem privaten Schlüssel zu entschlüsseln.

Warum bin ich verwirrt: Die Verschlüsselung/Entschlüsselung funktioniert, wenn ich den Verweis auf RSACryptoServiceProvider selbst übergebe:

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

Aber wenn der Export und übergeben Sie die RSAParameter:

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

... es wird ein "Schlüssel ausgegeben, der für den angegebenen Status nicht gültig ist." Ausnahme beim Versuch, den privaten Schlüssel nach RSAParameter zu exportieren. Bitte beachten Sie, dass das Zertifikat, aus dem die PFX generiert wurde, als exportierbar markiert ist (d. H., Ich habe beim Erstellen des Zertifikats das pe-Flag verwendet). Irgendeine Idee, was die Ausnahme verursacht?

 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);
}

Nur um im obigen Code zu verdeutlichen, wirft der fette Teil: string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);

52
kalrashi

Ich glaube, das Problem könnte sein, dass der Schlüssel nicht als exportierbar markiert ist. Es gibt einen anderen Konstruktor für X509Certificate2, das eine X509KeyStorageFlags-Aufzählung annimmt. Versuchen Sie, die Zeile zu ersetzen:

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

Mit diesem:

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

Für das Problem stellte ich fest, dass eine Codeänderung keine Option war, da dieselbe Bibliothek installiert war und an anderer Stelle funktionierte.

Die Antwort von Iridium veranlasste mich, den Schlüssel exportierbar zu machen, und ich konnte dies als Teil des MMC Certificate Import Wizard.

Hoffe das hilft jemand anderem. Tausend Dank

Cert import wizard

13
will webster

Ich bin auf ein ähnliches Problem gestoßen, und X509KeyStorageFlags.Exportable mein problem gelöst.

8
user1187372

Ich bin nicht gerade ein Experte in diesen Dingen, aber ich habe schnell google gemacht und Folgendes herausgefunden:

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

"Wenn Ihr Byte-Array mehr als 245 Bytes enthält, die Sie an Ihre RSACryptoServiceProvider.Encrypt-Methode (Byte [] rgb, Bool fOAEP) übergeben, wird eine Ausnahme ausgelöst."

3
Jeroen Jacobs

Für andere, die hier über Google landen, aber kein X509Certificate2 verwenden, erhalten Sie diese Nachricht auch, wenn Sie ToXmlString für RSACryptoServiceProvider aufrufen, aber nur einen öffentlichen Schlüssel geladen haben. Das Update ist das (beachten Sie die letzte Zeile):

var rsaAlg = new RSACryptoServiceProvider();

rsaAlg.ImportParameters(rsaParameters);

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

AFAIK das sollte funktionieren und du triffst wahrscheinlich einen Bug/einige Einschränkungen. Hier sind einige Fragen, die Ihnen helfen können, herauszufinden, wo das Problem liegt.

  • Wie haben Sie die PKCS # 12 (PFX) -Datei erstellt? Ich habe einige Schlüssel gesehen, die CryptoAPI nicht mag (ungewöhnliche RSA-Parameter). Können Sie ein anderes Tool verwenden (nur um sicherzugehen)?

  • Können Sie die PrivateKey -Instanz nach XML exportieren, z. ToXmlString(true), dann laden (importieren) Sie es auf diese Weise zurück?

  • Alte Versionen des Frameworks hatten einige Probleme beim Importieren eines Schlüssels, der eine andere Größe als die aktuelle Instanz hatte (standardmäßig 1024 Bit). Wie groß ist Ihr öffentlicher RSA-Schlüssel in Ihrem Zertifikat?

Beachten Sie auch, dass dies nicht ​​ist, wie Sie Daten mit RSA verschlüsseln sollten. Die Größe der Raw-Verschlüsselung ist auf den verwendeten öffentlichen Schlüssel begrenzt. Wenn Sie diese Grenze überschreiten, erhalten Sie nur wirklich schlechte Leistung.

Der Trick besteht darin, einen symmetrischen Algorithmus (wie AES ) mit einem total zufälligen Schlüssel zu verwenden und diesen Schlüssel dann zu verschlüsseln (wrap ) mit dem öffentlichen RSA-Schlüssel. C # -Code dazu finden Sie in meinem alten Blogeintrag zum Thema.

1
poupou