it-swarm.com.de

So lesen Sie einen privaten PEM RSA-Schlüssel aus .NET

Ich habe einen RSA-privaten Schlüssel im PEM-Format. Gibt es eine direkte Möglichkeit, diesen von .NET aus zu lesen und eine RSACryptoServiceProvider zu instanziieren, um mit dem entsprechenden öffentlichen Schlüssel verschlüsselte Daten zu entschlüsseln?

56
Simone

Ich habe es gelöst, danke. Für den Fall, dass jemand interessiert ist, hat bouncycastle den Trick ausgeführt, ich habe nur einige Zeit gebraucht, weil ich nicht über meine Kenntnisse und die Dokumentation informiert war. Dies ist der Code:

var bytesToDecrypt = Convert.FromBase64String("la0Cz.....D43g=="); // string to decrypt, base64 encoded

AsymmetricCipherKeyPair keyPair; 

using (var reader = File.OpenText(@"c:\myprivatekey.pem")) // file containing RSA PKCS1 private key
    keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject(); 

var decryptEngine = new Pkcs1Encoding(new RsaEngine());
decryptEngine.Init(false, keyPair.Private); 

var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length)); 
44
Simone

In Bezug auf das einfache Importieren des privaten RSA-Schlüssels ohne Verwendung von Drittanbieter-Code wie BouncyCastle, denke ich, lautet die Antwort "Nein, nicht mit einer PEM des privaten Schlüssels allein."

Wie bereits erwähnt, können Sie das PEM des privaten Schlüssels (* .key) und die Zertifikatsdatei mit diesem Schlüssel (* .crt) einfach zu einer * .pfx-Datei kombinieren, die dann einfach importiert werden kann.

So generieren Sie die PFX-Datei über die Befehlszeile:

openssl pkcs12 -in a.crt -inkey a.key -export -out a.pfx

Dann normalerweise mit der .NET-Zertifikatsklasse verwenden, z.

using System.Security.Cryptography.X509Certificates;

X509Certificate2 combinedCertificate = new X509Certificate2(@"C:\path\to\file.pfx");

Nun können Sie dem Beispiel aus MSDN zum Ver- und Entschlüsseln über den RSACryptoServiceProvider folgen:

Ich habe ausgelassen, dass Sie zum Entschlüsseln mit dem PFX-Passwort und dem Exportable-Flag importieren müssten. (siehe: BouncyCastle RSAPrivateKey zu .NET RSAPrivateKey )

X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);

RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true); 
25
SeventhPath

Sie können einen Blick auf JavaScience source für OpenSSLKey werfen. ( OpenSSLKey.cs )

Dort gibt es Code, der genau das tut, was Sie tun möchten.

In der Tat haben sie eine Menge Krypto-Quellcode hier verfügbar .


Quellcode-Ausschnitt:

//------- Parses binary ans.1 RSA private key; returns RSACryptoServiceProvider  ---
public static RSACryptoServiceProvider DecodeRSAPrivateKey(byte[] privkey)
{
        byte[] MODULUS, E, D, P, Q, DP, DQ, IQ ;

        // ---------  Set up stream to decode the asn.1 encoded RSA private key  ------
        MemoryStream  mem = new MemoryStream(privkey) ;
        BinaryReader binr = new BinaryReader(mem) ;    //wrap Memory Stream with BinaryReader for easy reading
        byte bt = 0;
        ushort twobytes = 0;
        int elems = 0;
        try {
                twobytes = binr.ReadUInt16();
                if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81)
                        binr.ReadByte();        //advance 1 byte
                else if (twobytes == 0x8230)
                        binr.ReadInt16();       //advance 2 bytes
                else
                        return null;

                twobytes = binr.ReadUInt16();
                if (twobytes != 0x0102) //version number
                        return null;
                bt = binr.ReadByte();
                if (bt !=0x00)
                        return null;


                //------  all private key components are Integer sequences ----
                elems = GetIntegerSize(binr);
                MODULUS = binr.ReadBytes(elems);

                elems = GetIntegerSize(binr);
                E = binr.ReadBytes(elems) ;

                elems = GetIntegerSize(binr);
                D = binr.ReadBytes(elems) ;

                elems = GetIntegerSize(binr);
                P = binr.ReadBytes(elems) ;

                elems = GetIntegerSize(binr);
                Q = binr.ReadBytes(elems) ;

                elems = GetIntegerSize(binr);
                DP = binr.ReadBytes(elems) ;

                elems = GetIntegerSize(binr);
                DQ = binr.ReadBytes(elems) ;

                elems = GetIntegerSize(binr);
                IQ = binr.ReadBytes(elems) ;

                Console.WriteLine("showing components ..");
                if (verbose) {
                        showBytes("\nModulus", MODULUS) ;
                        showBytes("\nExponent", E);
                        showBytes("\nD", D);
                        showBytes("\nP", P);
                        showBytes("\nQ", Q);
                        showBytes("\nDP", DP);
                        showBytes("\nDQ", DQ);
                        showBytes("\nIQ", IQ);
                }

                // ------- create RSACryptoServiceProvider instance and initialize with public key -----
                RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
                RSAParameters RSAparams = new RSAParameters();
                RSAparams.Modulus =MODULUS;
                RSAparams.Exponent = E;
                RSAparams.D = D;
                RSAparams.P = P;
                RSAparams.Q = Q;
                RSAparams.DP = DP;
                RSAparams.DQ = DQ;
                RSAparams.InverseQ = IQ;
                RSA.ImportParameters(RSAparams);
                return RSA;
        }
        catch (Exception) {
                return null;
        }
        finally {
                binr.Close();
        }
}
22
wprl

Das Zeug zwischen den 

-----BEGIN RSA PRIVATE KEY---- 

und 

-----END RSA PRIVATE KEY----- 

ist die base64-Kodierung eines PKCS # 8 PrivateKeyInfo (es sei denn, es wird RSA ENCRYPTED PRIVATE KEY angegeben. In diesem Fall handelt es sich um einen EncryptedPrivateKeyInfo).

Es ist nicht so schwer, manuell zu decodieren, aber ansonsten ist es am besten, wenn Sie auf CryptImportPKCS8 setzen.


Update: Die Funktion CryptImportPKCS8 ist ab Windows Server 2008 und Windows Vista nicht mehr verfügbar. Verwenden Sie stattdessen die Funktion PFXImportCertStore.

4
Rasmus Faber

ok, ich verwende mac, um meine selbstsignierten Schlüssel zu generieren. Hier ist die Arbeitsmethode, die ich verwendet habe.

Ich habe ein Shell-Skript erstellt, um die Schlüsselgenerierung zu beschleunigen.

genkey.sh

#/bin/sh

ssh-keygen -f Host.key
openssl req -new -key Host.key -out request.csr
openssl x509 -req -days 99999 -in request.csr -signkey Host.key -out server.crt
openssl pkcs12 -export -inkey Host.key -in server.crt -out private_public.p12 -name "SslCert"
openssl base64 -in private_public.p12 -out Base64.key

fügen Sie dem Skript das Ausführungsflag + x hinzu

chmod +x genkey.sh

rufen Sie dann genkey.sh auf

./genkey.sh

Ich gebe ein Passwort ein (wichtig, um wenigstens ein Passwort für den Export am Ende anzugeben)

Enter pass phrase for Host.key:
Enter Export Password:   {Important to enter a password here}
Verifying - Enter Export Password: { Same password here }

Ich nehme dann alles in Base64.Key und füge es in einen String namens sslKey ein

private string sslKey = "MIIJiAIBA...................................." +
                        "......................ETC...................." +
                        "......................ETC...................." +
                        "......................ETC...................." +
                        ".............ugICCAA=";

Ich habe dann einen Lazy Load Property Getter verwendet, um mein X509 Cert mit einem privaten Schlüssel zu erhalten.

X509Certificate2 _serverCertificate = null;
X509Certificate2 serverCertificate{
    get
    {
        if (_serverCertificate == null){
            string pass = "Your Export Password Here";
            _serverCertificate = new X509Certificate(Convert.FromBase64String(sslKey), pass, X509KeyStorageFlags.Exportable);
        }
        return _serverCertificate;
    }
}

Ich wollte diesen Weg gehen, weil ich .net 2.0 und Mono auf Mac verwende und Vanilla Framework-Code ohne kompilierte Bibliotheken oder Abhängigkeiten verwenden wollte. 

Mein letzter Einsatz war der SslStream, um die Kommunikation von TCP mit meiner App zu sichern 

SslStream sslStream = new SslStream(serverCertificate, false, SslProtocols.Tls, true);

Ich hoffe das hilft anderen Leuten.

HINWEIS

Ohne Passwort konnte ich den privaten Schlüssel nicht ordnungsgemäß für den Export entsperren.

2
The Lazy Coder

Überprüfen Sie http://msdn.Microsoft.com/de-de/library/dd203099.aspx

unter Cryptography Application Block.

Ich weiß nicht, ob Sie Ihre Antwort erhalten, aber es ist einen Versuch wert.

Nach Kommentar bearbeiten.

Ok, dann überprüfe diesen Code.

using System.Security.Cryptography;


public static string DecryptEncryptedData(stringBase64EncryptedData, stringPathToPrivateKeyFile) { 
    X509Certificate2 myCertificate; 
    try{ 
        myCertificate = new X509Certificate2(PathToPrivateKeyFile); 
    } catch{ 
        throw new CryptographicException("Unable to open key file."); 
    } 

    RSACryptoServiceProvider rsaObj; 
    if(myCertificate.HasPrivateKey) { 
         rsaObj = (RSACryptoServiceProvider)myCertificate.PrivateKey; 
    } else 
        throw new CryptographicException("Private key not contained within certificate."); 

    if(rsaObj == null) 
        return String.Empty; 

    byte[] decryptedBytes; 
    try{ 
        decryptedBytes = rsaObj.Decrypt(Convert.FromBase64String(Base64EncryptedData), false); 
    } catch { 
        throw new CryptographicException("Unable to decrypt data."); 
    } 

    //    Check to make sure we decrpyted the string 
   if(decryptedBytes.Length == 0) 
        return String.Empty; 
    else 
        return System.Text.Encoding.UTF8.GetString(decryptedBytes); 
} 
1
João Augusto

Ich habe die PemUtils-Bibliothek erstellt, die genau das tut. Der Code steht auf GitHub zur Verfügung und kann von NuGet installiert werden:

PM> Install-Package PemUtils

oder wenn Sie nur einen DER-Konverter wünschen:

PM> Install-Package DerConverter

Verwendung zum Lesen eines RSA-Schlüssels aus PEM-Daten:

using (var stream = File.OpenRead(path))
using (var reader = new PemReader(stream))
{
    var rsaParameters = reader.ReadRsaKey();
    // ...
}
0
huysentruitw

Für Leute, die Bouncy nicht verwenden möchten und einige der in anderen Antworten enthaltenen Codes ausprobieren, habe ich herausgefunden, dass der Code meistens funktioniert, aber einige private RSA-Zeichenfolgen auftaucht, wie die von mir habe unten aufgenommen. Durch den Blick auf den Bouncy-Code habe ich den von wprl bereitgestellten Code angepasst 

    RSAparams.D = ConvertRSAParametersField(D, MODULUS.Length);
    RSAparams.DP = ConvertRSAParametersField(DP, P.Length);
    RSAparams.DQ = ConvertRSAParametersField(DQ, Q.Length);
    RSAparams.InverseQ = ConvertRSAParametersField(IQ, Q.Length);

    private static byte[] ConvertRSAParametersField(byte[] bs, int size)
    {
        if (bs.Length == size)
            return bs;

        if (bs.Length > size)
            throw new ArgumentException("Specified size too small", "size");

        byte[] padded = new byte[size];
        Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
        return padded;
    }

-----BEGIN RSA PRIVATE KEY-----
MIIEoQIBAAKCAQEAxCgWAYJtfKBVa6Px1Blrj+3Wq7LVXDzx+MiQFrLCHnou2Fvb
fxuDeRmd6ERhDWnsY6dxxm981vTlXukvYKpIZQYpiSzL5pyUutoi3yh0+/dVlsHZ
UHheVGZjSMgUagUCLX1p/augXltAjgblUsj8GFBoKJBr3TMKuR5TwF7lBNYZlaiR
k9MDZTROk6MBGiHEgD5RaPKA/ot02j3CnSGbGNNubN2tyXXAgk8/wBmZ4avT0U4y
5oiO9iwCF/Hj9gK/S/8Q2lRsSppgUSsCioSg1CpdleYzIlCB0li1T0flB51zRIpg
JhWRfmK1uTLklU33xfzR8zO2kkfaXoPTHSdOGQIDAQABAoIBAAkhfzoSwttKRgT8
sgUYKdRJU0oqyO5s59aXf3LkX0+L4HexzvCGbK2hGPihi42poJdYSV4zUlxZ31N2
XKjjRFDE41S/Vmklthv8i3hX1G+Q09XGBZekAsAVrrQfRtP957FhD83/GeKf3MwV
Bhe/GKezwSV3k43NvRy2N1p9EFa+i7eq1e5i7MyDxgKmja5YgADHb8izGLx8Smdd
+v8EhWkFOcaPnQRj/LhSi30v/CjYh9MkxHMdi0pHMMCXleiUK0Du6tnsB8ewoHR3
oBzL4F5WKyNHPvesYplgTlpMiT0uUuN8+9Pq6qsdUiXs0wdFYbs693mUMekLQ4a+
1FOWvQECgYEA7R+uI1r4oP82sTCOCPqPi+fXMTIOGkN0x/1vyMXUVvTH5zbwPp9E
0lG6XmJ95alMRhjvFGMiCONQiSNOQ9Pec5TZfVn3M/w7QTMZ6QcWd6mjghc+dGGE
URmCx8xaJb847vACir7M08AhPEt+s2C7ZokafPCoGe0qw/OD1fLt3NMCgYEA08WK
S+G7dbCvFMrBP8SlmrnK4f5CRE3pV4VGneWp/EqJgNnWwaBCvUTIegDlqS955yVp
q7nVpolAJCmlUVmwDt4gHJsWXSQLMXy3pwQ25vdnoPe97y3xXsi0KQqEuRjD1vmw
K7SXoQqQeSf4z74pFal4CP38U3pivvoE4MQmJeMCfyJFceWqQEUEneL+IYkqrZSK
7Y8urNse5MIC3yUlcose1cWVKyPh4RCEv2rk0U1gKqX29Jb9vO2L7RflAmrLNFuA
J+72EcRxsB68RAJqA9VHr1oeAejQL0+JYF2AK4dJG/FsvvFOokv4eNU+FBHY6Tzo
k+t63NDidkvb5jIF6lsCgYEAlnQ08f5Y8Z9qdCosq8JpKYkwM+kxaVe1HUIJzqpZ
X24RTOL3aa8TW2afy9YRVGbvg6IX9jJcMSo30Llpw2cl5xo21Dv24ot2DF2gGN+s
peFF1Z3Naj1Iy99p5/KaIusOUBAq8pImW/qmc/1LD0T56XLyXekcuK4ts6Lrjkit
FaMCgYAusOLTsRgKdgdDNI8nMQB9iSliwHAG1TqzB56S11pl+fdv9Mkbo8vrx6g0
NM4DluCGNEqLZb3IkasXXdok9e8kmX1en1lb5GjyPbc/zFda6eZrwIqMX9Y68eNR
IWDUM3ckwpw3rcuFXjFfa+w44JZVIsgdoGHiXAdrhtlG/i98Rw==
-----END RSA PRIVATE KEY-----
0
Jack Bond