Generate key/Encryption/Decryption for RSACryptoProvider and BouncyCastle - c#

Key generated through RSACryptoProvider is work for BouncyCastle Encryption (using publickey) / Decryption (using privatekey) ?
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
var pu = rsa.ToXmlString(false);
var pr = rsa.ToXmlString(true);
}
Also, how to generate key using BouncyCastle ?

Answer to first question, yes, RSA is a standard and it doesn't depends on the libraries used.
Second, try this:
public static void GetRsaKeyPair(out string privateXml, out string publicXml)
{
CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
SecureRandom secureRandom = new SecureRandom(randomGenerator);
var keyGenerationParameters = new KeyGenerationParameters(secureRandom, 1024);
var rsaKeyPairGenerator = new RsaKeyPairGenerator();
rsaKeyPairGenerator.Init(keyGenerationParameters);
AsymmetricCipherKeyPair rsaKeyPair = rsaKeyPairGenerator.GenerateKeyPair();
var privateRsaParameters = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)rsaKeyPair.Private);
using (RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider())
{
rsaProvider.ImportParameters(privateRsaParameters);
privateXml = rsaProvider.ToXmlString(true);
publicXml = rsaProvider.ToXmlString(false);
}
}

Related

Get public key from private key in Bouncy Castle C#

So I have an encrypted private key PEM. I can read it and get the private key with the following:
AsymmetricKeyParameter key;
using (var sr = new StringReader(pem))
using (var pf = new PassowrdFinder { Password = password })
{
var reader = new PemReader(sr, pf);
key = (AsymmetricKeyParameter)reader.ReadObject();
}
I also need the public key, to create the SPKI later on. I tried
var keyPair = new AsymmetricCipherKeyPair(key, key);
Which fails with System.ArgumentException: Expected a public key Parameter name: publicParameter.
My question is: How to get the public key from a private key?
Thanks to help from James K Polk, here is what I came up with
AsymmetricCipherKeyPair GetKeyPairFromPrivateKey(AsymmetricKeyParameter privateKey)
{
AsymmetricCipherKeyPair keyPair = null;
if (privateKey is RsaPrivateCrtKeyParameters rsa)
{
var pub = new RsaKeyParameters(false, rsa.Modulus, rsa.PublicExponent);
keyPair = new AsymmetricCipherKeyPair(pub, privateKey);
}
else if (privateKey is Ed25519PrivateKeyParameters ed)
{
var pub = ed.GeneratePublicKey();
keyPair = new AsymmetricCipherKeyPair(pub, privateKey);
}
else if (privateKey is ECPrivateKeyParameters ec)
{
var q = ec.Parameters.G.Multiply(ec.D);
var pub = new ECPublicKeyParameters(ec.AlgorithmName, q, ec.PublicKeyParamSet);
keyPair = new AsymmetricCipherKeyPair(pub, ec);
}
if (keyPair == null)
throw new NotSupportedException($"The key type {privateKey.GetType().Name} is not supported.");
return keyPair;
}
It should be very simple:
AsymmetricCipherKeyPair KeyPair = (AsymmetricCipherKeyPair)reader.ReadObject();
Then:
var pubKey = KeyPair.public;
I'm a little clumsy with the Bouncycastle C# library but I think the way to do this is to explicitly make a new key object using the appropriate components of the private key. Example
// Make an rsa keypair for testing
var rand = new SecureRandom();
var keyGenParams = new RsaKeyGenerationParameters(
new BigInteger("65537"), rand, 1024, 64
);
var rsaKeyGen = new RsaKeyPairGenerator();
rsaKeyGen.Init(keyGenParams);
var rsaKeyPair = rsaKeyGen.GenerateKeyPair();
var rsaPriv = (RsaPrivateCrtKeyParameters)rsaKeyPair.Private;
// Make a public from the private
var rsaPub = new RsaKeyParameters(false, rsaPriv.Modulus, rsaPriv.PublicExponent);
// Try it out
var rsaKeyPair2 = new AsymmetricCipherKeyPair(rsaPub, rsaPriv);
The downside of this approach is that it requires a concrete instance of a specific kind of asymmetric key; it does not work with the abstract asymmetric key classes.

How to import Firebase Private Key into C#?

I would like to know how Firebase key could be imported to c#
and being used as SingingCredintials for JWT?
private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAAS\n-----END PRIVATE KEY-----\n",
I have tried the following so far, but it bring wrong signing algorithm not RS256
RsaPrivateCrtKeyParameters key;
using (StringReader sr = new StringReader(fbPrivateKey)) //here used StringReader
{
PemReader pr = new PemReader(sr);
key = (RsaPrivateCrtKeyParameters)pr.ReadObject(); //no more keyPair because I just have the privKey only
}
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters(key);
RSACryptoServiceProvider rsa;
rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(rsaParams);
var nRsa = PemKeyUtils.GetRSAProviderFromPemFile(fbPrivateKey);
Microsoft.IdentityModel.Tokens.RsaSecurityKey _signingKey = new Microsoft.IdentityModel.Tokens.RsaSecurityKey(nRsa);
Microsoft.IdentityModel.Tokens.SigningCredentials signingCredentials =
new Microsoft.IdentityModel.Tokens.SigningCredentials(_signingKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.RsaSha256);
Also I have tried this with no success
string jwt = string.Empty;
RsaPrivateCrtKeyParameters keyPair;
using (StringReader sr = new StringReader(fbPrivateKey)) //here used StringReader
{
PemReader pr = new PemReader(sr);
keyPair = (RsaPrivateCrtKeyParameters)pr.ReadObject(); //no more keyPair because I just have the privKey only
}
RSAParameters rsaParams = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)keyPair);
It bring the keyid null and the algorithim rsa-sha1, which is supposed to be rsa256.

how to encrypt and decrypt with only public key with rsa c#

I want to encrypt and decrypt the RSA using only the public key, but I get an error on the decryption side. Error: "unknown block type"
Can you help?
BigInteger rsaPubMod = new BigInteger(Base64.Decode("ALGZqqOFBDh6qULIV0hf5g+Zg5uQqTYWhrw9fzUJwWL8dW7V6kd+9kO8yD+1/f8NVmSDAWGfmVImsPNZp/8x/tF/DycPi5vfRuzHfFcT0mSgD7VW2CfuKM0Gh2WOpgXct6IMC7UsWTkPf8VBSgHobbkr+Ex5pm09mooe2KXTtXN3"));
BigInteger rsaPubExp = new BigInteger(Base64.Decode("AQAB"));
Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keyPair = new AsymmetricCipherKeyPair(new RsaKeyParameters(false, rsaPubMod, rsaPubExp), new RsaKeyParameters(true, rsaPubMod,rsaPubExp));
RsaKeyParameters pubParameters = new RsaKeyParameters(false, rsaPubMod, rsaPubExp);
IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(true, pubParameters);
byte[] encdata = Convert.FromBase64String("test");
var encdataResult = eng.ProcessBlock(encdata, 0, encdata.Length);
string result = Convert.ToBase64String(encdataResult);
IAsymmetricBlockCipher deng = new Pkcs1Encoding(new RsaEngine());
deng.Init(false, pubParameters);
byte[] decdata = Convert.FromBase64String(result);
var dencdataResult = deng.ProcessBlock(decdata, 0, decdata.Length);
string result2 = Encoding.UTF8.GetString(dencdataResult);
RSA is an asymmetric algorithm. With a public key you can encrypt, or perform signature verification. With a private key you can decrypt, perform signature creation, or create a public key.

RSA Decryption using BouncyCastle with private PEM file not working

I'm doing some tests with BouncyCastle in C# and I want to encrypt some data and decrypt it later with a pair of keys that I have in my computer stored as PEM files.
public static string RSABouncyEncrypt(string content)
{
var bytesToEncrypt = Encoding.UTF8.GetBytes(content);
AsymmetricKeyParameter keyPair;
using (var reader = File.OpenText(#"C:\Users\Diego\Documents\public.pem")))
keyPair = (AsymmetricKeyParameter)new org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();
var engine = new RsaEngine();
engine.Init(true, keyPair);
var encrypted = engine.ProcessBlock(bytesToEncrypt, 0, bytesToEncrypt.Length);
var cryptMessage = Convert.ToBase64String(encrypted);
Logs.Log.LogMessage("encrypted: " + cryptMessage);
System.Windows.MessageBox.Show(cryptMessage);
//Decrypt before return statement to check that it has been encrypted correctly
RSADecrypt(cryptMessage);
return cryptMessage;
}
public static void RSADecrypt(string string64)
{
var bytesToDecrypt = Convert.FromBase64String(string64); // string to decrypt, base64 encoded
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"C:\Users\Diego\Documents\private.pem"))
keyPair = (AsymmetricCipherKeyPair)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();
var decryptEngine = new RsaEngine();
decryptEngine.Init(false, keyPair.Private);
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
Logs.Log.LogMessage("decrypted: " + decrypted);
System.Windows.MessageBox.Show(decrypted);
}
The RSADecrypt function shows an error. when I show the message box after decrypting I get this:
���Z��8o>>���;;�/�Z�ב?���#�F��(͌5���o1I�,���4� S�W��)��w��x�4p�$-|А���&��Rv}�G��V�c ��&wU?
�D�� }E���O����7�n��!(e��E��$y�g9ςOأ��P�� �t�d�T�nN��K$�bQ��!�v���-�Hb���1���?����#B�y� r��Le�h=*Yr�w
�l�W|�嘟��|g��EV��#�[��M
which is definitely not what I encrypted. What am I doing wrong?
Actually the answer why it is not working is that there is no information about padding. Correct way how to instantiate RsaEngine is sth. like this
var decryptEngine = new Pkcs1Encoding(RsaEngine())
var bytesToDecrypt = Convert.FromBase64String(string64); // string to decrypt, base64 encoded
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"C:\Users\Diego\Documents\private.pem"))
keyPair = (AsymmetricCipherKeyPair)new Org.BouncyCastle.OpenSsl.PemReader(reader).ReadObject();
var decryptEngine = new Pkcs1Encoding(RsaEngine());
decryptEngine.Init(false, keyPair.Private);
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
Logs.Log.LogMessage("decrypted: " + decrypted);
System.Windows.MessageBox.Show(decrypted);
I reproduced this problem and it happened because you used a private key and a public key that don't match. In other words the message was encrypted with a private key (let's call it private_key_1) that came from one pair (private_key_1/public_key_1) but you tried to decrypt it with a public key (let's call it publick_key_2) that came from a different pair (private_key_2/public_key_2). Try to generate a new key pair and use it in your example e.g.:
var kpgen = new RsaKeyPairGenerator();
kpgen.Init(new KeyGenerationParameters(new SecureRandom(new CryptoApiRandomGenerator()), 1024));
var keyPair = kpgen.GenerateKeyPair();
using (var writer = new StreamWriter(File.OpenWrite(#"C:\Users\Diego\Documents\private2.pem")))
{
new PemWriter(writer).WriteObject(keyPair.Private);
}
using (var writer = new StreamWriter(File.OpenWrite(#"C:\Users\Diego\Documents\public2.pem")))
{
new PemWriter(writer).WriteObject(keyPair.Public);
}

Encode a RSA public key to DER format

I need a RSA public key encoded into DER format.
The key-pair is generated using RSACryptoServiceProvider.
What I'm looking for is the c# equivalent to the java:
PublicKey pubKey = myPair.getPublic();
byte[] keyBytes = pubKey.getEncoded();
I have tried looking into BouncyCastle but got lost so if the solution is there any pointers are welcome.
Using Bouncy Castle:
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
...
var generator = new RsaKeyPairGenerator ();
generator.Init (new KeyGenerationParameters (new SecureRandom (), 1024));
var keyPair = generator.GenerateKeyPair ();
RsaKeyParameters keyParam = (RsaKeyParameters)keyPair.Public;
var info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo (keyParam);
RsaBytes = info.GetEncoded ();
The last three lines are the ones who take the RSA public key and export it.
I tried to use aforementioned info.GetEncoded() but as a result, I couldn't use it to verify the signature created with the corresponding private key.
What works for me is converting it to a X509Certificate2.
private bool VerifySignature(string stringContent, string stringSignature, X509Certificate2 x509PublicKey)
{
Int16 cbSignature = 0, cbCert = 0;
int cbData = 0;
CertBasicStruct sCert = new CertBasicStruct();
var pbCert = PublicKey.RawData;
cbCert = (Int16)pbCert.Length;
byte[] pbData = Encoding.UTF8.GetBytes(stringContent);
cbData = (Int16)pbData.Length;
byte[] pbSignature = Convert.FromBase64String(Signature);
cbSignature = (Int16)pbSignature.Length;
var rtn = DllImportService.DecodeCertificate(pbCert, cbCert, ref sCert);
var rtn_1 = DllImportService.VerifySignatureByCert(ref sCert, DllImportService.CKM_SHA256_RSA_PKCS, pbData, cbData, pbSignature, cbSignature);
if (rtn_1 == 0)
{
LogWndAppendLine("Signature is valid.");
return true;
}
else
{
LogWndAppendLine("Signature is invalid");
return false;
}
}
X509Certificate2.RawData would be what you are looking for.

Categories

Resources