I have a random private key ("C:\tmp\private.key"
):
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDHikastc8+I81zCg/qWW8dMr8mqvXQ3qbPAmu0RjxoZVI47tvs
kYlFAXOf0sPrhO2nUuooJngnHV0639iTTEYG1vckNaW2R6U5QTdQ5Rq5u+uV3pMk
7w7Vs4n3urQ6jnqt2rTXbC1DNa/PFeAZatbf7ffBBy0IGO0zc128IshYcwIDAQAB
AoGBALTNl2JxTvq4SDW/3VH0fZkQXWH1MM10oeMbB2qO5beWb11FGaOO77nGKfWc
bYgfp5Ogrql4yhBvLAXnxH8bcqqwORtFhlyV68U1y4R+8WxDNh0aevxH8hRS/1X5
031DJm1JlU0E+vStiktN0tC3ebH5hE+1OxbIHSZ+WOWLYX7JAkEA5uigRgKp8ScG
auUijvdOLZIhHWq7y5Wz+nOHUuDw8P7wOTKU34QJAoWEe771p9Pf/GTA/kr0BQnP
QvWUDxGzJwJBAN05C6krwPeryFKrKtjOGJIniIoY72wRnoNcdEEs3HDRhf48YWFo
riRbZylzzzNFy/gmzT6XJQTfktGqq+FZD9UCQGIJaGrxHJgfmpDuAhMzGsUsYtTr
iRox0D1Iqa7dhE693t5aBG010OF6MLqdZA1CXrn5SRtuVVaCSLZEL/2J5UcCQQDA
d3MXucNnN4NPuS/L9HMYJWD7lPoosaORcgyK77bSSNgk+u9WSjbH1uYIAIPSffUZ
bti+jc1dUg5wb+aeZlgJAkEAurrpmpqj5vg087ZngKfFGR5rozDiTsK5DceTV97K
a3Y+Nzl+XWTxDBWk4YPh2ZlKv402hZEfWBYxUDn5ZkH/bw==
-----END RSA PRIVATE KEY-----
I tried to use the RSACryptoServiceProvider.ImportCspBlob
to import it but it failed with the error:
System.Security.Cryptography.CryptographicException: Bad Version of provider.
Full stack trace:
Failed: System.Security.Cryptography.CryptographicException: Bad Version of provider.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.Utils._ImportCspBlob(Byte[] keyBlob, SafeProvHandle hProv, CspProviderFlags flags, SafeKeyHandle& hKey)
at System.Security.Cryptography.Utils.ImportCspBlobHelper(CspAlgorithmType keyType, Byte[] keyBlob, Boolean publicOnly, CspParameters& parameters, Boolean randomKeyContainer, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.ImportCspBlob(Byte[] keyBlob)
at ConsoleApplication3.Program.DecodeRSA(Byte[] data, Int32 c_data) in C:\Users\myuser\Documents\Visual Studio 2015\Projects\myproj\ConsoleApplication3\Program.cs:line 28
at ConsoleApplication3.Program.Main(String[] args) in C:\Users\myuser\Documents\Visual Studio 2015\Projects\myproj\ConsoleApplication3\Program.cs:line 14
Press any key to continue . . .
Any idea what I am doing wrong?
This is my code:
using System;
using System.Security.Cryptography;
namespace ConsoleApplication3
{
class Program
{
static public byte[] privateKey;
static void Main(string[] args)
{
try
{
privateKey = System.IO.File.ReadAllBytes(@"C:\tmp\private.key");
DecodeRSA(privateKey);
}
catch(Exception e)
{
Console.WriteLine("Failed: {0}", e);
}
}
static public void DecodeRSA(byte[] data)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.ImportCspBlob(Program.privateKey);
}
}
}
}
Your private key has a PKCS1-PEM-Format. Private key BLOBs have another format. As already mentioned in the comments, the formats are very different and cannot be easily converted (see e.g. here). Of course you can use a PKCS1-PEM-key, but it is not that easy. Here are some options:
Possibility 1:
If you use .NET Core 3.0 there is a direct support for reading a PKCS1-key (see also here):
byte[] privateKeyPkcs1PEM = File.ReadAllBytes(@"C:\tmp\private.key"); // PKCS1 - PEM
byte[] privateKeyPkcs1DER = ConvertPKCS1PemToDer(Encoding.UTF8.GetString(privateKeyPkcs1PEM));
RSA rsa = RSA.Create();
rsa.ImportRSAPrivateKey(privateKeyPkcs1DER, out _);
// use e.g. rsa.Decrypt(...)
However, the ImportRSAPrivateKey
-method can only process the DER-format which is essentially the binary format of the PEM-format (for more details see here or here). Thus, you have to convert the PEM-format into the DER-format with something like
private static byte[] ConvertPKCS1PemToDer(string pemContents)
{
return Convert.FromBase64String(pemContents
.TrimStart("-----BEGIN RSA PRIVATE KEY-----".ToCharArray())
.TrimEnd("-----END RSA PRIVATE KEY-----".ToCharArray())
.Replace("\r\n",""));
}
Alternatively, OpenSSL can also be used for the conversion:
openssl rsa -inform PEM -outform DER -in C:\tmp\private.key -out C:\tmp\private.der
Possibility 2:
You can convert your PKCS1-PEM-key into an PKCS8-DER-key using OpenSSL. The appropriate command is:
openssl pkcs8 -topk8 -inform pem -in C:\tmp\private.key -outform der -nocrypt -out C:\tmp\privatepkcs8.der
The difference between PKCS1- and PKCS8-format is explained here. Then you can import the key with built-in .NET-methods (see also here, section PKCS#8 PrivateKeyInfo):
byte[] privateKeyPkcs8DER = File.ReadAllBytes(@"C:\tmp\privatepkcs8.der"); // PKCS8 - DER
CngKey cngKey = CngKey.Import(privateKeyPkcs8DER, CngKeyBlobFormat.Pkcs8PrivateBlob);
RSA rsa = new RSACng(cngKey);
// use e.g. rsa.Decrypt(...)
Possibility 3:
If third-party-libraries may be used, BouncyCastle is also a possibility:
StreamReader reader = File.OpenText(@"C:\tmp\private.key"); // PKCS1 - PEM
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(reader).ReadObject();
Pkcs1Encoding pkcs1Encoding = new Pkcs1Encoding(new RsaEngine());
// E.g. decryption
pkcs1Encoding.Init(false, keyPair.Private);
byte[] decrypted = pkcs1Encoding.ProcessBlock(encrypted, 0, encrypted.Length);
Possibility 4:
Another possibility is the use of the DecodeRSAPrivateKey
-method from JavaScience
which can process a PKCS1-key. However, the DecodeRSAPrivateKey
-method can only process the DER-format. Thus, you must first manually convert the PEM-format into the DER-format using e.g. ConvertPKCS1PemToDer
or OpenSSL.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With