RSA public key to base 64 - c#

I have generated and RSA public key :
RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(4096);
var pub_key = rsaProvider.ExportParameters(false); // export public key
var priv_key = rsaProvider.ExportParameters(true); // export private key
I need a way to decode pub_key it into base64 so I can send it, any suggestions

When you say Base64 do you mean that you need the public key in Base64 PEM format? If so, consider using BouncyCastle.
var kp = [Org.BouncyCastle.Security.DotNetUtilities].GetKeyPair(rsaProvider);
using (var sw = new System.IO.StringWriter())
{
var pw = new Org.BouncyCastle.OpenSsl.PemWrite(sw);
pw.WriteObject(kp.Public);
var pem = sw.ToString();
return pem;
}

It is not clear exactly what you need but I'm guessing you are looking to serialize the key. In that case you can use the RSA.ToXmlString() method. If you really need to base64 encode it then you the method in Nickolay Olshevsky's answer to further encode the XML string.

In .NET there is a builtin function to convert to Base64 : http://msdn.microsoft.com/en-us/library/dhx0d524.aspx

Related

C# - Load .DER public key from file and use for encryption

I have a public key in a .der extension file from a vendor. I have to use this to encrypt something using C# and add the result to an API call. I am new to this type of stuff and can't figure out how to load the key in the .der file into code and use it to encrypt my string. Any help?
Thanks!
You can use the X509Certificate2 to load the certificate, I.E.:
var cert = new X509Certificate2(#"C:\path\to\key.der");
var publicKey = cert.GetRSAPublicKey();
var privateKey = cert.GetRSAPrivateKey();
To actually encrypt/decrypt data, you would do something similar to the following depending on the specifications
var plaintext = Encoding.UTF8.GetBytes("Some Secret");
var encrypted = publicKey.Encrypt(plaintext, RSAEncryptionPadding.OaepSHA256);
var decrypted = privateKey.Decrypt(encrypted, RSAEncryptionPadding.OaepSHA256);
Console.WriteLine(Encoding.UTF8.GetString(decrypted));

Initializing RSA from String

I am trying to decrypt some text that is encrypted with RSA, I have the public key to do this
`
-----BEGIN RSA PUBLIC KEY-----
MIGWAoGBAMqfGO9sPz+kxaRh/qVKsZQGul7NdG1gonSS3KPXTjtcHTFfexA4MkGA
mwKeu9XeTRFgMMxX99WmyaFvNzuxSlCFI/foCkx0TZCFZjpKFHLXryxWrkG1Bl9+
+gKTvTJ4rWk1RvnxYhm3n/Rxo2NoJM/822Oo7YBZ5rmk8NuJU4HLAhAYcJLaZFTO
sYU+aRX4RmoF
-----END RSA PUBLIC KEY-----
`
How can I load this into RSACryptoServiceProvider because this can only load from XMLString and I do not know how to convert this to Xml format
The key size is 128
I tried to initialize it using the following code
public byte[] Decrypt128(byte[] input)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(128);
rsa.ImportCspBlob(Encoding.ASCII.GetBytes(_longKey));
return rsa.Decrypt(input, true);
}
_longKey is the content between BEGIN and END and also including the BEGIN and END, bot Bad Version of provider.
This is not a duplicate question of How do you convert Byte Array to Hexadecimal String, and vice versa?
I already know how to convert byte to hex and hex to byte, but that in any way does not help me initializing RSACryptoServiceProvider maybe give me example how that would help but at this point it doesn't
You could use BouncyCastle which has a PemReader allowing you to extract the modulus and exponent for the key:
using (var reader = File.OpenText("mykey.key"))
{
var pem = new PemReader(reader);
var o = (RsaKeyParameters)pem.ReadObject();
using (var rsa = new RSACryptoServiceProvider())
{
var parameters = new RSAParameters();
parameters.Modulus = o.Modulus.ToByteArray();
parameters.Exponent = o.Exponent.ToByteArray();
rsa.ImportParameters(parameters);
// Do what you need to do with the RSACryptoServiceProvider instance
}
}
If you don't want to have a dependency on BouncyCastle in your project, once loaded the public key into the RSACryptoServiceProvider using this method you could export it to XML for future use:
string xml = rsa.ToXmlString(false);
File.WriteAllText("mykey.xml", xml);

How to validate public key xml file?

I have created a public key using RSACryptoServiceProvider in c#.
Later in my program I want to store it's content in database. How can I make sure that the file is a true public key.
Note: I have checked it's structure against xsd. but I need more.
Any help?
the code to produce public key:
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
string publicKey = rsa.ToXmlString(false);
finally I've found a solution:
first I check the schema against a xsd file,
and then
try
{
var csp = new RSACryptoServiceProvider();
var reader = new StreamReader(address);
var xml = reader.ReadToEnd();
csp.FromXmlString(xml);
}
catch
{
//not a rsa public key
}

How to get private key from PKCS#12 (.p12) file using C#

Im trying to sign some data using PKCS#12 certificate ,however i have problem with obtaining private key from PKCS#12 (.p12) file.
public byte[] sign(string text)
{
string password = "1111";
X509Certificate2 cert = new X509Certificate2("c:\\certificate.p12",password);
byte[] certData = cert.Export(X509ContentType.Pfx,password);
X509Certificate2 newCert = new X509Certificate2(certData, password);
RSACryptoServiceProvider crypt = (RSACryptoServiceProvider)newCert.PrivateKey;
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
return crypt.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
}
The problem is that newCert.PrivateKey is null but if i am using .pfx certicitae in similar way it works.
public byte[] sign(string text)
{
string password = "1234";
X509Certificate2 cert = new X509Certificate2("c:\\certificate.pfx", password);
RSACryptoServiceProvider crypt = (RSACryptoServiceProvider)cert.PrivateKey;
SHA1Managed sha1 = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1.ComputeHash(data);
return crypt.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"));
}
So the question is how to get that private key from .p12 file ?
I had a similar problem which I posted here, although it is not the same thing for you, the problem may be also permissions.
My suggestions are, first, you have to make sure (which I suppose you already did) that the private key is exportable and you have permissions to the file.
Next, try exporting the content type as X509ContentType.Pkcs12 instead of X509ContentType.Pfx
Finally, if it is possible, why don't you try importing it to the certstore. I believe that's more secure. The steps are in the link above.
Have a look at this question. It looks very similar.
In the docs, it says that .export() doesn't support the Pfx type, only Cert, SerializedCert, and Pkcs12.
This was done for using Android - so the R.raw.key below was my file in the Android Raw folder.
I opened key.p12 as as input stream. Which I then converted to the private key using the libraries as seen in the example.
http://www.flexiprovider.de/examples/ExampleSMIMEsign.html
My code looks like this
Security.addProvider(new de.flexiprovider.core.FlexiCoreProvider());
// Next, we have to read the private PKCS #12 file, since the the
// private key used for signing is contained in this file:
DERDecoder dec = new DERDecoder(getResources().openRawResource(
R.raw.key));
PFX pfx = new PFX();
try {
pfx.decode(dec);
SafeBag safeBag = pfx.getAuthSafe().getSafeContents(0)
.getSafeBag(0);
PKCS8ShroudedKeyBag kBag = (PKCS8ShroudedKeyBag) safeBag
.getBagValue();
char[] password = "my password for the p12".toCharArray();
privKey = kBag.getPrivateKey(password);
new AsyncLoadStorage(this).execute();
} catch (ASN1Exception e) {

Sign data with MD5WithRSA from .Pem/.Pkcs8 keyfile in C#

I've got the following code sample in Java, and I need to re-enact it in C#:
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(pkcs8PrivateKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
Signature sign = Signature.getInstance("MD5withRSA");
sign.initSign(privKey);
sign.update(data);
byte[] signature = sign.sign();
Is it possible with the standard .Net Crypto API, or should I use BouncyCastle?
Thanks,
b.
Another way is to use CNG (Cryptography Next Generation), along with the Security.Cryptography DLL from CodePlex
Then you can write:
byte[] dataToSign = Encoding.UTF8.GetBytes("Data to sign");
using (CngKey signingKey = CngKey.Import(pkcs8PrivateKey, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSACng rsa = new RSACng(signingKey))
{
rsa.SignatureHashAlgorithm = CngAlgorithm.MD5;
return rsa.SignData(dataToSign);
}
Updated thanks to Simon Mourier: with .Net 4.6, you no longer need a separate library
I am running into a very similar problem trying to create a native C# tool for packing Chrome extensions (using SHA1, not MD5, but that's not a big difference). I believe I have tried literally every possible solution for .Net: System.Security.Cryptography, BouncyCastle, OpenSSL.Net and Chilkat RSA.
The best solution is probably Chilkat; their interface is the cleanest and most straightforward, it's well-supported and well-documented, and there are a million examples. For instance, here's some code using their library that does something very close to what you want: http://www.example-code.com/csharp/rsa_signPkcs8.asp. However, it's not free (though $150 is not unreasonable, seeing as I have burned 2 days trying to figure this out, and I make a bit more than $75 a day!).
As a free alternative, JavaScience offers up a number of crypto utilities in source form for multiple languages (including C#/.Net) at http://www.jensign.com/JavaScience/cryptoutils/index.html. The one that's most salient to what you are trying to do is opensslkey (http://www.jensign.com/opensslkey/index.html), which will let you generate a RSACryptoServiceProvider from a .pem file. You can then use that provider to sign your code:
string pemContents = new StreamReader("pkcs8privatekey.pem").ReadToEnd();
var der = opensslkey.DecodePkcs8PrivateKey(pemContents);
RSACryptoServiceProvider rsa = opensslkey.DecodePrivateKeyInfo(der);
signature = rsa.SignData(data, new MD5CryptoServiceProvider());
You can use this code . At the first you should download "BouncyCastle.Crypto.dll" from http://www.bouncycastle.org/csharp/ .
/// <summary>
/// MD5withRSA Signing
/// https://www.vrast.cn
/// keyle_xiao 2017.1.12
/// </summary>
public class MD5withRSASigning
{
public Encoding encoding = Encoding.UTF8;
public string SignerSymbol = "MD5withRSA";
public MD5withRSASigning() { }
public MD5withRSASigning(Encoding e, string s)
{
encoding = e;
SignerSymbol = s;
}
private AsymmetricKeyParameter CreateKEY(bool isPrivate, string key)
{
byte[] keyInfoByte = Convert.FromBase64String(key);
if (isPrivate)
return PrivateKeyFactory.CreateKey(keyInfoByte);
else
return PublicKeyFactory.CreateKey(keyInfoByte);
}
public string Sign(string content, string privatekey)
{
ISigner sig = SignerUtilities.GetSigner(SignerSymbol);
sig.Init(true, CreateKEY(true, privatekey));
var bytes = encoding.GetBytes(content);
sig.BlockUpdate(bytes, 0, bytes.Length);
byte[] signature = sig.GenerateSignature();
/* Base 64 encode the sig so its 8-bit clean */
var signedString = Convert.ToBase64String(signature);
return signedString;
}
public bool Verify(string content, string signData, string publickey)
{
ISigner signer = SignerUtilities.GetSigner(SignerSymbol);
signer.Init(false, CreateKEY(false, publickey));
var expectedSig = Convert.FromBase64String(signData);
/* Get the bytes to be signed from the string */
var msgBytes = encoding.GetBytes(content);
/* Calculate the signature and see if it matches */
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(expectedSig);
}
}
This SO question answers the PKCS#8 part of your code. The rest of the .NET RSA classes are a bizarre jumble of partially overlapping classes that are very difficult to fathom. It certainly appears that signature support is in either of the RSACryptoServiceProvider and/or RSAPKCS1SignatureFormatter classes.
Disclaimer: I know Java and cryptography, but my knowledge of C# and .NET is very limited. I am writing here only under the influence of my Google-fu skills.
Assuming that you could decode a PKCS#8-encoded RSA private key, then, from what I read on MSDN, the rest of the code should look like this:
byte[] hv = MD5.Create().ComputeHash(data);
RSACryptoServiceProvider rsp = new RSACryptoServiceProvider();
RSAParameters rsp = new RSAParameters();
// here fill rsp fields by decoding pkcs8PrivateKey
rsp.ImportParameters(key);
RSAPKCS1SignatureFormatter rf = new RSAPKCS1SignatureFormatter(rsp);
rf.SetHashAlgorithm("MD5");
byte[] signature = rf.CreateSignature(hv);
The relevant classes are in the System.Security.Cryptography namespace.
As for the PKCS#8 key blob decoding (i.e. filling in the rsp fields), I found this page which describes a command-line utility in C# which can perform that job. The source code is provided and is a single C# file. From what I read in it, that code decodes the PKCS#8 file "manually"; indirectly, this should mean that raw .NET (2.0) does not have facilities for PKCS#8 key file decoding (otherwise the author of that tool would not have went to the trouble of implementing such decoding). For your task at hand, you could scavenge from that source file the parts that you need, skipping anything about PEM and symmetric encryption; your entry point would be the DecodePrivateKeyInfo() function, which apparently expects a DER-encoded unencrypted PKCS#8 file, just like Java's PKCS8EncodedKeySpec.

Categories

Resources