Comment lire une clé privée PEM RSA from.NET

j'ai une clé privée RSA dans le format PEM , y a-t-il un moyen simple de lire cela à partir de .NET et instancier un RSACryptoServiceProvider pour déchiffrer des données cryptées avec la clé publique correspondante?

54
demandé sur Irshad 2008-10-28 18:03:37

8 réponses

j'ai résolu, merci. Dans le cas où n'importe qui est intéressé, bouncycastle fait le tour, juste pris un certain temps en raison du manque de connaissances de mon côté et de la documentation. C'est le 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)); 
42
répondu Simone 2015-06-16 00:19:14

en ce qui concerne l'importation facile de la clé privée RSA, sans utiliser le code tiers tel que BouncyCastle, je pense que la réponse est" non, pas avec un PEM de la clé privée seule."

cependant, comme mentionné ci-dessus par Simone, vous pouvez simplement combiner le PEM de la clé privée (*.la clé) et le fichier de certificat à l'aide de cette touche (*.crt) dans un *.fichier pfx qui peut ensuite être facilement importées.

pour générer le fichier PFX à partir de la ligne de commande:

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

utiliser alors normalement avec la classe de certificat .NET telle que:

using System.Security.Cryptography.X509Certificates;

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

Maintenant, vous pouvez suivre l'exemple de MSDN pour le chiffrement et le déchiffrement via RSACryptoServiceProvider:

j'ai omis que pour décrypter vous auriez besoin d'importer en utilisant le mot de passe PFX et le drapeau Exportable. (voir: 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); 
24
répondu SeventhPath 2017-05-23 10:31:16

, Vous pouvez prendre un coup d'oeil à JavaScience source OpenSSLKey . ( OpenSSLKey.cs )

Il y a un code qui fait exactement ce que vous voulez faire.

en fait, ils ont beaucoup de code source crypto disponible ici .


extrait de code Source:

//------- 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();
        }
}
20
répondu wprl 2012-10-09 19:51:50

La choses entre le

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

et

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

est l'encodage base64 d'un PKCS#8 PrivateKeyInfo (à moins qu'il ne s'agisse d'une clé privée cryptée RSA, auquel cas il s'agit d'un Privatekeyinfo crypté).

il n'est pas si difficile de décoder manuellement, mais autrement votre meilleur pari est D'invoquer à CryptImportPKCS8 .


Mise à jour: la fonction CryptImportPKCS8 n'est plus disponible depuis Windows Server 2008 et Windows Vista. Utilisez plutôt la fonction PFXImportCertStore .

4
répondu Rasmus Faber 2012-10-09 19:05:33

ok, J'utilise mac pour générer mes propres clés signées. Voici la méthode de travail que j'ai utilisée.

j'ai créé un script shell pour accélérer ma génération de clés.

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

ajouter le drapeau + x execute au script

chmod +x genkey.sh

alors appelez genkey.sh

./genkey.sh

j'entre un mot de passe (important d'inclure un mot de passe au moins pour l'exportation à la fin)

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

je prends alors tout en Base64.La clé et le mettre dans une chaîne appelée sslKey

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

j'ai ensuite utilisé un getter de propriété load lazy pour obtenir mon x509 Cert avec une clé privée.

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

je voulais suivre cette route parce que j'utilise .net 2.0 et Mono sur mac et je voulais utiliser du code de Framework vanilla sans bibliothèques compilées ou dépendances.

mon utilisation finale pour ceci était le SslStream pour sécuriser la communication TCP pour mon application

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

j'espère que cela aidera d'autres personnes.

NOTE

sans mot de passe, je n'ai pas pu déverrouiller correctement la clé privée pour l'exportation.

2
répondu The Lazy Coder 2013-10-25 00:34:19

Check http://msdn.microsoft.com/en-us/library/dd203099.aspx

sous le bloc D'Application cryptographique.

Je ne sais pas si vous obtiendrez votre réponse, mais cela vaut la peine d'essayer.

Modifier après le Commentaire de .

vérifiez ce 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
répondu João Augusto 2013-03-22 17:28:27

pour les gens qui ne veulent pas utiliser Bouncy, et qui essayent certains du code inclus dans d'autres réponses, j'ai trouvé que le code fonctionne la plupart du temps, mais trébuche sur certaines cordes privées RSA, comme celle que j'ai incluse ci-dessous. En regardant le code bouncy, j'ai modifié le code fourni par wprl à

    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
répondu Jack Bond 2017-04-30 21:46:37

j'ai créé la bibliothèque PemUtils qui fait exactement cela. Le code est disponible sur GitHub et peut être installé à partir de NuGet :

PM> Install-Package PemUtils

ou si vous voulez seulement un convertisseur DER:

PM> Install-Package DerConverter

Utilisation pour la lecture d'une clé RSA de PEM de données:

using (var stream = File.OpenRead(path))
using (var reader = new PemReader(stream))
{
    var rsaParameters = reader.ReadRsaKey();
    // ...
}
0
répondu Housy 2018-07-18 08:44:27