web-dev-qa-db-ja.com

.NETからPEM RSA秘密キーを読み取る方法

RSA形式のPEM秘密鍵を持っています。それを.NETから読み取り、RSACryptoServiceProviderをインスタンス化して対応する暗号化されたデータを復号化する簡単な方法はありますか公開鍵?

61
Simone

解決しました、ありがとう。誰かが興味を持っている場合は、 bouncycastle がうまくいきました。私の側からの知識とドキュメントが不足しているため、少し時間がかかりました。これはコードです:

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)); 
49
Simone

BouncyCastleなどのサードパーティコードを使用せずにRSA秘密鍵を簡単にインポートすることに関しては、答えは「いいえ、秘密鍵のPEMだけではない」と思います。

ただし、上記でシモーヌが示唆したように、秘密キー(* .key)のPEMとそのキー(* .crt)を使用する証明書ファイルを* .pfxファイルに単純に結合して、簡単にインポートできます。

コマンドラインからPFXファイルを生成するには:

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

次に、次のような.NET証明書クラスで通常使用します。

using System.Security.Cryptography.X509Certificates;

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

[〜#〜] msdn [〜#〜] の例に従って、RSACryptoServiceProviderを介した暗号化と復号化を行うことができます。

復号化には、PFXパスワードとExportableフラグを使用してインポートする必要があることを除外しました。 (参照: 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); 
27
SeventhPath

JavaScience's source for OpenSSLKey をご覧ください。

あなたがやりたいことを正確に行うコードがそこにあります。

実際、彼らは多くの暗号化ソースコードを持っています こちらから入手可能


ソースコードスニペット:

//------- 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();
        }
}
23
wprl

の間のもの

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

そして

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

pKCS#8 PrivateKeyInfoのbase64エンコードです(RSA ENCRYPTED PRIVATE KEYがEncryptedPrivateKeyInfoである場合を除きます)。

手動でデコードするのはそれほど難しくありませんが、そうでなければ、P/Invoke to CryptImportPKCS8 にするのが最善の策です。


更新:CryptImportPKCS8関数はno Windows Server 2008およびWindows Vista以降で使用できるようになりました。代わりに、PFXImportCertStore関数を使用します。

4
Rasmus Faber

わかりました、自己署名キーを生成するためにMacを使用しています。これが私が使用した作業方法です。

キー生成を高速化するシェルスクリプトを作成しました。

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

スクリプトに+ x実行フラグを追加します

chmod +x genkey.sh

次に、genkey.shを呼び出します

./genkey.sh

パスワードを入力します(少なくとも最後にエクスポート用のパスワードを含めることが重要です)

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

次に、Base64.Keyのすべてを取得し、sslKeyという名前の文字列に入れます

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

次に、遅延読み込みプロパティゲッターを使用して、プライベートキーを持つX509証明書を取得しました。

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

Macで.net 2.0とMonoを使用しており、コンパイルされたライブラリや依存関係のないVanilla Frameworkコードを使用したかったため、このルートにしたかったのです。

これの最終的な用途は、SslStreamでTCPアプリとの通信を保護することでした

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

これが他の人に役立つことを願っています。

[〜#〜] note [〜#〜]

パスワードがないと、エクスポートのために秘密鍵を正しくロック解除できませんでした。

2
The Lazy Coder

チェック http://msdn.Microsoft.com/en-us/library/dd203099.aspx

暗号化アプリケーションブロックの下。

答えが得られるかどうかはわかりませんが、試してみる価値はあります。

コメント後に編集

OK、このコードを確認してください。

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

まさにそれを行うPemUtilsライブラリを作成しました。コードは GitHub で入手でき、 NuGet からインストールできます。

PM> Install-Package PemUtils

または、DERコンバーターのみが必要な場合:

PM> Install-Package DerConverter

PEMデータからRSAキーを読み取るための使用法:

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

Bouncyを使用したくなく、他の回答に含まれるコードの一部を試している人のために、コードはほとんどの時間で動作することを発見しましたが、以下を含めました。弾むコードを見て、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
Jack Bond