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.
Related
Essentially, I'm looking to convert a Public Microsoft.IdentityModel.Tokens.JsonWebKey.JsonWebKey to RSAParameters to then use in an RSA Instance. After this, i'm creating an Azure KeyVault JsonWebKey so I can import this key into my vault. I currently tried this, however have not gotten it to work. Any recommendations/shortcuts?
var jwk = new JsonWebKey(someStr); // IdentityModel.Tokens...
var rsaParams = new RSAParameters
{
Modulus = WebEncoders.Base64UrlDecode(jwk.N),
Exponent = WebEncoders.Base64UrlDecode(jwk.E)
};
var rsa = RSA.Create(rsaParams);
var key = new JsonWebKey(rsa); // Azure.Security.KeyVault.Keys
....
var kvKey = keyClient.ImportKey(keyName, key); // keyClient = KeyClient class
The error I am receiving from this request is:
RSA key is not valid - cannot instantiate crypto service
Try adding other rsa parameters and then importing into an RSACryptoServiceProvider. Then you can recover the SecurityKey.
The code below is an example of how to recover a SecurityKey from a previous RSASecurityKey stored in a JsonWebKey
using RSACryptoServiceProvider provider = new RSACryptoServiceProvider(2048);
JsonWebKey key = JsonConvert.DeserializeObject<JsonWebKey>(jsonwebkeystringcontent);
RSAParameters rsaParameters = new()
{
Modulus = WebEncoders.Base64UrlDecode(key.N),
Exponent = WebEncoders.Base64UrlDecode(key.E),
D = WebEncoders.Base64UrlDecode(key.D),
DP = WebEncoders.Base64UrlDecode(key.DP),
DQ = WebEncoders.Base64UrlDecode(key.DQ),
P = WebEncoders.Base64UrlDecode(key.P),
Q = WebEncoders.Base64UrlDecode(key.Q),
InverseQ = WebEncoders.Base64UrlDecode(key.QI)
};
provider.ImportParameters(rsaParameters);
SecurityKey Key = new RsaSecurityKey(provider.ExportParameters(true));
I generate an ECC key pair in PEM format using Bouncy Castle using:
var curve = ECNamedCurveTable.GetByName("secp256k1");
var domainParams = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed());
var secureRandom = new SecureRandom();
var keyParams = new ECKeyGenerationParameters(domainParams, secureRandom);
var generator = new ECKeyPairGenerator("ECDSA");
generator.Init(keyParams);
AsymmetricCipherKeyPair keyPair = generator.GenerateKeyPair();
TextWriter textWriter = new StringWriter();
PemWriter pemWriter = new PemWriter(textWriter);
pemWriter.WriteObject(keyPair.Private);
pemWriter.Writer.Flush();
string pem_privatekey = textWriter.ToString();
My current ECC private key is:
-----BEGIN EC PRIVATE KEY-----MIIBUQIBAQQgyDHBaj30dcIsS4otdOXR8ue+rZDwHcGEjxwle3H24W6ggeMwgeACAQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wvMEQEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwRBBHm+Zn753LusVaBilc6HCwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ1LgCIQD////////////////////+uq7c5q9IoDu/0l6M0DZBQQIBAaFEA0IABHxw0PK0uEvnF1lwhkLmHUlVtQVUrLp/1EcKzfAm6xOL/I6LtQ9nXPxDNhaxf/rPtk3DkZ5CaO0hLr1trCRrJz8=-----END EC PRIVATE KEY-----
I want to read this pem format private in a bouncy castle ECPrivateKeyParameters or AsymmetricCipherKeyPair format.
I am trying the following code.
pem is the above private key string.
PemReader pr = new PemReader(new StringReader(pem));
ECPrivateKeyParameters KeyPair = (ECPrivateKeyParameters)pr.ReadObject();
Why this returns null? Please correct me.
pr.ReadObject() returns an AsymmetricCipherKeyPair instance here. This has the properties Private and Public which here returns an ECPrivateKeyParameters and ECPublicKeyParameters instance respectively, i.e. the code should be:
PemReader pr = new PemReader(new StringReader(pem));
AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)pr.ReadObject();
ECPrivateKeyParameters privateKeyParams = (ECPrivateKeyParameters)keyPair.Private;
ECPublicKeyParameters publicKeyParams = (ECPublicKeyParameters)keyPair.Public; // for completeness
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);
}
}
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.
Sample code:
CspParameters cspParameters = new CspParameters();
cspParameters.ProviderType = 1; // PROV_RSA_FULL
// Create the crypto service provider, generating a new
// key.
mRsaCSP = new RSACryptoServiceProvider(mDefaultKeyLength, cspParameters);
mRsaCSP.PersistKeyInCsp = true;
RSAParameters privateKey = mRsaCSP.ExportParameters(true);
byte[] rsaBytes = mRsaCSP.ExportCspBlob(true);
try
{
X509Certificate2 cert = new X509Certificate2(rsaBytes);
mKeyDataPfx = Convert.ToBase64String(cert.Export(X509ContentType.Pkcs12, password));
}
catch (Exception ce)
{
string error = ce.Message;
}
Here is my solution, using the BouncyCastle library.
// create the RSA key from an XML string
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(keyTextBox.Text);
// convert to BouncyCastle key object
var keypair = DotNetUtilities.GetRsaKeyPair(key);
var gen = new X509V3CertificateGenerator();
string certName = Path.GetFileNameWithoutExtension(fileName);
var name = new X509Name("CN=" + certName);
var serial = BigInteger.ProbablePrime(120, new Random());
gen.SetSerialNumber(serial);
gen.SetSubjectDN(name);
gen.SetIssuerDN(name);
gen.SetNotAfter(DateTime.Now.AddYears(10));
gen.SetNotBefore(DateTime.Now);
gen.SetSignatureAlgorithm("MD5WithRSA");
gen.SetPublicKey(keypair.Public);
// generate the certificate
var newCert = gen.Generate(keypair.Private);
// convert back to .NET certificate
var cert = DotNetUtilities.ToX509Certificate(newCert);
// export as byte array
byte[] certData = cert.Export(X509ContentType.Pfx);
File.WriteAllBytes(fileName, certData);