Как читать закрытый ключ PEM RSA из .NET.

У меня есть закрытый ключ 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)); 

Что касается простого импорта частного ключа RSA, без использования стороннего кода, такого как BouncyCastle, я думаю, что ответ «Нет, не с помощью PEM только частного ключа».

Однако, как упоминалось выше, Simone, вы можете просто объединить PEM закрытого ключа (* .key) и файл сертификата с помощью этого ключа (* .crt) в файл * .pfx, который затем можно легко импортировать.

Чтобы создать файл PFX из командной строки:

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

Затем обычно используйте class сертификата .NET, например:

 using System.Security.Cryptography.X509Certificates; X509Certificate2 combinedCertificate = new X509Certificate2(@"C:\path\to\file.pfx"); 

Теперь вы можете следовать примеру MSDN для шифрования и дешифрования через RSACryptoServiceProvider:

Я забыл, что для дешифрования вам нужно будет импортировать, используя пароль PFX и флаг Exportable. (см .: BouncyCastle RSAPrivateKey для .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 . ( OpenSSLKey.cs )

Там есть код, который делает именно то, что вы хотите сделать.

На самом деле, у них есть много исходного кода crypto, доступного здесь .


Исходный код:

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

является кодировкой base64 PKCS # 8 PrivateKeyInfo (если только он не сообщает RSA ENCRYPTED PRIVATE KEY, в этом случае это EncryptedPrivateKeyInfo).

Это не так сложно декодировать вручную, но в противном случае лучше всего сделать P / Invoke для 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="; 

Затем я использовал ленивую загрузку Property getter, чтобы получить мой сертификат 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; } } 

Я хотел пойти по этому маршруту, потому что я использую .net 2.0 и Mono на Mac, и я хотел использовать код Vanilla Framework без компилированных библиотек или зависимостей.

Моим окончательным использованием для этого был SslStream для обеспечения связи TCP с моим приложением

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

Надеюсь, это поможет другим людям.

ЗАМЕТКА

Без пароля мне не удалось правильно разблокировать закрытый ключ для экспорта.

Проверьте http://msdn.microsoft.com/en-us/library/dd203099.aspx

в блоке приложения криптографии.

Не знаю, получишь ли ты свой ответ, но стоит попробовать.

Редактировать после комментария .

Тогда проверьте этот код.

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

Для людей, которые не хотят использовать Bouncy, и пытаются использовать некоторые из кодов, включенных в другие ответы, я обнаружил, что код работает MOST того времени, но отправляется на некоторые частные строки RSA, такие как тот, который я «Включено ниже». Посмотрев на полезный код, я изменил код, предоставленный 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----- 

Я создал библиотеку PemUtils, которая делает именно это. Код доступен в GitHub и может быть установлен из NuGet :

 PM> Install-Package PemUtils 

или если вы хотите только конвертер DER:

 PM> Install-Package DerConverter 

Использование для считывания ключа RSA из данных PEM:

 using (var stream = File.OpenRead(path)) using (var reader = new PemReader(stream)) { var rsaParameters = reader.ReadRsaKey(); // ... } 
  • Использование AES-шифрования в C #
  • Как я могу создать криптографически безопасное псевдослучайное число в C #?
  • Генерация ключей шифрования / дешифрования Java openssl
  • Атрибуты AES-NI включены по умолчанию?
  • Почему мне нужно использовать class Rfc2898DeriveBytes (в .NET) вместо прямого использования пароля в качестве ключа или IV?
  • Фундаментальное различие между алгоритмами Hashing и Encryption
  • Почему при использовании функции Non-Random IV с режимом CBC существует уязвимость?
  • Шифрование файлов cookie в ASP.NET
  • Что делает оператор?
  • Зачем использовать class C # System.Random вообще, а не System.Security.Cryptography.RandomNumberGenerator?
  • Как hash строку в Android?
  • Давайте будем гением компьютера.