UFO ET IT

.NET에서 PEM RSA 개인 키를 읽는 방법

ufoet 2020. 11. 27. 21:48
반응형

.NET에서 PEM RSA 개인 키를 읽는 방법


내가 가지고 RSA있는 개인 키 PEM형식을 .NET에서 해당 읽어와의 인스턴스를 정직 방법이 RSACryptoServiceProvider대응하는 공개 키를 사용하여 암호화 복호화 데이터는?


고마워요. 누군가가 관심이 있다면 , 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)); 

BouncyCastle과 같은 타사 코드를 사용하지 않고 RSA 개인 키를 쉽게 가져올 수 있다는 점에서 대답은 "아니요, 개인 키의 PEM만으로는 안됩니다"라고 생각합니다.

그러나 Simone이 위에서 언급했듯이 개인 키 (* .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); 

당신은 한 번 봐 걸릴 수 있습니다 JavaScience의 의 소스 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();
        }
}

사이의 물건

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

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

PKCS # 8 PrivateKeyInfo의 base64 인코딩입니다 (RSA ENCRYPTED PRIVATE KEY라고 표시되지 않는 한,이 경우 EncryptedPrivateKeyInfo 인 경우).

수동으로 디코딩하는 것은 그리 어렵지 않지만 그렇지 않은 경우 가장 좋은 방법은 P / Invoke to CryptImportPKCS8 입니다.


업데이트 : CryptImportPKCS8의 기능이 더 이상 Windows Server 2008 및 Windows Vista의로 사용할 수 있습니다. 대신 PFXImportCertStore 함수를 사용하십시오 .


좋아, 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=";

그런 다음 lazy load Property getter를 사용하여 개인 키로 X509 Cert를 가져 왔습니다.

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를 사용하고 있고 컴파일 된 라이브러리 나 종속성없이 바닐라 프레임 워크 코드를 사용하고 싶었 기 때문에이 경로를 가고 싶었습니다.

이것에 대한 마지막 용도는 내 앱에 대한 TCP 통신을 보호하기위한 SslStream이었습니다.

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

이것이 다른 사람들에게 도움이되기를 바랍니다.

노트

비밀번호가 없으면 내보내기를 위해 개인 키를 올바르게 잠금 해제 할 수 없습니다.


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

Cryptography Application Block 아래에 있습니다.

답을 얻을 수 있을지 모르겠지만 시도해 볼 가치가 있습니다.

댓글 후 편집 .

좋아,이 코드를 확인하십시오.

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

For people who don't want to use Bouncy, and are trying some of the code included in other answers, I've found that the code works MOST of the time, but trips up on some RSA private strings, such as the one I've included below. By looking at the bouncy code, I tweaked the code provided by wprl to

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

I've created the PemUtils library that does exactly that. The code is available on GitHub and can be installed from NuGet:

PM> Install-Package PemUtils

or if you only want a DER converter:

PM> Install-Package DerConverter

Usage for reading a RSA key from PEM data:

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

참고URL : https://stackoverflow.com/questions/243646/how-to-read-a-pem-rsa-private-key-from-net

반응형