How to Read a Pem Rsa Private Key from .Net

How to read a PEM RSA private key from .NET


Update 03/03/2021

.NET 5 now supports this out of the box.

To try the code snippet below, generate a keypair and encrypt some text at http://travistidwell.com/jsencrypt/demo/

var privateKey = @"-----BEGIN RSA PRIVATE KEY-----
{ the full PEM private key }
-----END RSA PRIVATE KEY-----";

var rsa = RSA.Create();
rsa.ImportFromPem(privateKey.ToCharArray());

var decryptedBytes = rsa.Decrypt(
Convert.FromBase64String("{ base64-encoded encrypted string }"),
RSAEncryptionPadding.Pkcs1
);

// this will print the original unencrypted string
Console.WriteLine(Encoding.UTF8.GetString(decryptedBytes));

Original answer

I solved, thanks. In case anyone's interested, bouncycastle did the trick, just took me some time due to lack of knowledge from on my side and documentation. This is the 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));

How do I read RSA public key from PEM file and use it to encrypt in BouncyCastle in C#?

You're using the wrong PemReader, you want the one from Org.BouncyCastle.OpenSsl.

EDIT: For some reason OP is insistent that this class has no ReadObject method. It does, and it can be seen here.

Like this:

using System;
using System.IO;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

namespace ScratchPad
{
class MainClass
{
public static void Main(string[] args)
{
var pemReader = new PemReader(File.OpenText(@"/Users/horton/tmp/key-examples/myserver_pub.pem"));
var pemObject = (Org.BouncyCastle.Crypto.Parameters.RsaKeyParameters)pemReader.ReadObject();
var rsa = DotNetUtilities.ToRSA(pemObject);
// ... more stuff ...
}
}
}

RSA Encryption in C# PEM format

The posted key is an RSA key in X.509/SPKI format. PemReader expects a PEM encoded key. However, the posted key is not PEM encoded, it is missing header, footer and line breaks after every 64 characters. The PEM encoded key looks like this:

string publicKey = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlUCQZso6P43gKqw0CfTl
wYb3N+m4v6IME4nPA3WXe52wFpDM/JCFWSdXa7BewlwzDYjblgwL4u59CPxNTPTh
7LTD4xXOaGDJHjX5+YgqK4fb9rsImjMpIACrND/LAdrq5mctWWzw3UtW3F+o+sNw
IZM8n65ysS+Vhq9IypFlfuQbWrKjAcWZ3u1iLtplzyf/pjhOEyyZiBUnh6D219+p
MiE9nhCpc4xkH1gnlGszIDBqZMMULtGJvFXydA1vv5HxxCYJ2ydEzmAKYxVgA9BG
XPEGE89dQbeJsieTj+FSsp9oTm+4vi345opRvH8DWhmZc4OPSwBEL8pwgS7cUnKP
twIDAQAB
-----END PUBLIC KEY-----";

Regarding line breaks PemReader is tolerant: Only header and footer must be in separate lines.

Btw, as of .NET Core 3.0, import of a DER encoded RSA key in X.509/SPKI format is supported by RSA.ImportSubjectPublicKeyInfo(). As of .NET 5, import of PEM encoded RSA keys is supported with RSA.ImportFromPem().

Decrypting with private key from .pem file in c# with .NET crypto library

http://www.jensign.com/opensslkey/index.html

with source at http://www.jensign.com/opensslkey/opensslkey.cs
Update: Source code is no longer available at this url. It can be found at https://gist.github.com/stormwild/7887264 or https://web.archive.org/web/20170731015547/http://www.jensign.com/opensslkey/opensslkey.cs now.

edit: excerpted relevant code:

first, extract the text between the ---- BEGIN ---- and ---- END ---- sections, and base64-decode it into a byte array (see link above for details), then pass it to:

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


Related Topics



Leave a reply



Submit