2008-10-28 4 views
50

Ich habe einen RSA privaten Schlüssel im Format PEM, gibt es eine direkte Möglichkeit, das von .NET zu lesen und eine RSACryptoServiceProvider zu instanziieren, um Daten zu entschlüsseln, die mit den entsprechenden public verschlüsselt sind Schlüssel?Wie liest man einen privaten PEM RSA Schlüssel aus .NET

Antwort

41

Ich löste, danke. Falls irgendjemand interessiert ist, bouncycastle hat den Trick gemacht, nur hat mich einige Zeit wegen des Mangels an Wissen von meiner Seite und Dokumentation genommen. 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)); 
+3

Was ist Bouncycastle? – WildJoe

+37

@WildJoe: Entweder ein aufgeblasener Lebensraum für Monarchen, oder www.bouncycastle.org;) –

+1

was ist mit einem passwortgeschützten Zertifikat? – Sinaesthetic

19

Sie können sich ansehen JavaScience's Quelle für OpenSSLKey. (OpenSSLKey.cs)

Da ist Code drin, der genau das tut, was Sie tun möchten.

In der Tat haben sie eine Menge Crypto-Quellcode available here.


Quellcode-Schnipsel:

//------- 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(); 
     } 
} 
+0

Versuchte, nicht funktioniert, und hat nicht die Zeit durch den Code zu gehen, noch, würde ich hoffe, es war ein einfacher Lösung. – Simone

+0

Können Sie Einzelheiten darüber angeben, was fehlgeschlagen ist? Ich habe mir den Code angeschaut und es scheint, als müsste es funktionieren. Vielleicht könnten Sie sogar die PEM-Datei posten? (Wenn Sie eine nicht empfindliche haben). –

+1

Ich habe gerade diese Antwort von [dieser Frage SO] (http://stackoverflow.com/a/1162519/12597) gefunden. Jetzt, da ich sehe, dass es sich um tatsächliche Code-Dateien handelt, und sie buchstäblich nur die ASN.1-kodierten Daten dekodieren, verdient diese Antwort mehr +1. (Sie sollten sich wirklich nicht 'JavaScience' nennen) –

1

prüfen http://msdn.microsoft.com/en-us/library/dd203099.aspx

unter Cryptography Application Block.

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

Nach dem Kommentar bearbeiten.

Ok, dann überprüfen Sie 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); 
} 
+0

Nein, es unterstützt keine asymmetrischen Algorithmen. – Simone

+1

Dieser Code kann keinen PEM rsa privaten Schlüssel laden, er benötigt eine Zertifikatsdatei basierend auf diesem Schlüssel, die generiert werden kann, aber ich möchte diesen Schritt vermeiden. – Simone

+0

Ok, dann sag mir, wo hast du deinen privaten Schlüssel? –

4

Das Zeug zwischen dem

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

und

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

ist die Base64-Codierung eines PKCS # 8 PrivateKeyInfo (es sei denn, es in diesem Fall ist es RSA VERSCHLÜSSELTE PRIVATE KEY sagt, ist ein VerschlüsseltePrivatKeyInfo).

Es ist nicht so schwer, manuell zu dekodieren, aber sonst ist Ihre beste Wette, P/Invoke zu CryptImportPKCS8.


Update: Die CryptImportPKCS8 Funktion ist nicht mehr für die Verwendung als von Windows Server 2008 und Windows Vista. Verwenden Sie stattdessen die PFXImportCertStore Funktion.

21

Im Hinblick auf einfache Weise den privaten RSA-Schlüssel zu importieren, ohne 3rd-Party-Code wie BouncyCastle, ich denke, die Antwort ist „Nein, nicht mit einer PEM des privaten Schlüssels allein.“

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

Um die PFX-Datei von der Befehlszeile zu erzeugen:

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

dann normalerweise mit der .NET-Zertifikat Klasse verwenden, wie zum Beispiel:

using System.Security.Cryptography.X509Certificates; 

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

Jetzt können Sie das Beispiel aus MSDN folgen für die Verschlüsselung und entschlüsseln via RSACryptoServiceProvider:

Ich habe vergessen, dass Sie zum Entschlüsseln müssen Sie mit dem PFX-Passwort und der Exportable Fla importieren G. (Siehe: BouncyCastle RSAPrivateKey to .NET RSAPrivateKey)

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

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

ok, Im mac mit meinem selbst signiertes Schlüssel zu generieren. Hier ist die Arbeitsweise, die ich verwendet habe.

Ich habe ein Shell-Skript erstellt, um meine 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 

hinzufügen + x ausführen Flag, um das Skript

chmod +x genkey.sh 

dann rufen genkey.sh

./genkey.sh 

ich geben Sie ein Passwort (wichtig sind ein Passwort mindestens für den Export am Ende)

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 in einen sslKey

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

ich dann eine faule Last Property Getter verwendet benannte Zeichenfolge setzen, um meine X509 Cert mit einem privaten Schlüssel zu bekommen.

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 auf dem Mac bin mit .net 2.0 und Mono und ich wollte Vanille-Framework-Code ohne kompilierten Bibliotheken oder Abhängigkeiten verwenden.

Meine Endverwendung hierfür war die SslStream zu TCP-Kommunikation zu meinem app

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

Ich hoffe, das hilft andere Menschen zu sichern.

HINWEIS

Ohne ein Passwort, das ich nicht in der Lage war richtig für den Export, die privaten Schlüssel zu entsperren.

0

Für Leute, die Bouncy nicht verwenden möchten, und einige der Code in anderen Antworten enthalten, habe ich festgestellt, dass der Code die meiste Zeit funktioniert, aber auf einige private RSA-Strings, wie z als die, die ich unten eingeschlossen habe. Mit Blick auf die Hüpfburg Code, gezwickt ich die von wprl bereitgestellten Code zu

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-----