I have an ECC private and a certificate file which includes the public key. I can get them in either PEM or DER formats.
I can read the certificate into an X509Certificate with this code:
var certbytes = File.ReadAllBytes("certificate.pem");
var cert = new X509Certificate2(certbytes);
But I'm unable to load the private key. I've tried this code:
var keyContent = File.ReadAllBytes("certificate_private_key.pem");
var key = CngKey.Import(keyContent, CngKeyBlobFormat.EccPrivateBlob);
It throws Internal.Cryptography.CryptoThrowHelper.WindowsCryptographicException: 'An error occurred during encode or decode operation'.
I've also tried other values of the CngKeyBlobFormat parameter. The Import method fails with those as well.
openssl can read the file, and it outputs the following information about it:
openssl ec -in certificate_private_key.pem -text
read EC key
Private-Key: (256 bit)
priv:
44:<cut>:68
pub:
04:<cut>:13
ASN1 OID: prime256v1
NIST CURVE: P-256
writing EC key
-----BEGIN EC PRIVATE KEY-----
MHcC <cut here>
-----END EC PRIVATE KEY-----
Is there built-in API in .NET or .NET Core which can do this? Or are there 3rd party libraries that can do it, and how?
.NET Core 3.0 (currently in preview) has ECDsa.ImportECPrivateKey, AsymmetricAlgorithm.ImportPkcs8PrivateKey, and AsymmetricAlgorithm.ImportEncryptedPkcs8PrivateKey, (and RSA has RSAPublicKey and RSAPrivateKey) and for the current file (BEGIN EC PRIVATE KEY) you'd want the first one.
The good news of those methods is: they exist.
The bad news is: They're part of the next version, not the current one.
Good: The next version should be the current version soonishly.
Bad: They only understand BER/DER data, not PEM.
The last point means that you currently would have to find the base64 content between the -----BEGIN EC PRIVATE KEY-----\n and \n-----END EC PRIVATE KEY----- and de-base64-it, then pass that into the methods.
The only private key formats that I know that are supported by CNG import are PKCS8, encrypted PKCS8, and CNG private formats. To use CngKey.Import you'd first need to convert the keyfile to PKCS#8 then specify that the format is Pkcs8PrivateBlob, as suggested in the comments.
Related
I am trying to load an EC Private key from base64 string obtained from PEM file which was generated with openssl into a netfx4.8 application this is later used to create ECDsa key object.
I have noticed that we have a PEM reader in .Net5 so what are my options while staying in .Net4.8.
To make it clear we create keys with following openssl command
openssl ecparam -out ecc_private_key.key -name secp256r1 -genkey
which gives output into following format (This is an example key only - not used anywhere)
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIBfBTJGdjFUK2S0bTBWfogeRElTF52jjVjeSs2GvsIrvoAoGCCqGSM49
AwEHoUQDQgAEQEyYxahMyU6H7i4GkX0pzOtgNiJrwxLGSiLSgBgFjV/VfGIUjrQl
ia6+KPlQJd0IRtQLIG0kqXeD/yyeikuYBw==
-----END EC PRIVATE KEY-----
So we like to inject base64 contents available within "EC PRIVATE KEY" header/footer into the application.
Current workaround
Currently I am using following command to parse the contents and then injecting Private and Public key separately. this helps to remove unwanted headers available in PEM contents.
$ openssl ec -in ecc_private_key.key -noout -text
read EC key
Private-Key: (256 bit)
priv:
17:c1:4c:91:9d:8c:55:0a:d9:2d:1b:4c:15:9f:a2:
07:91:12:54:c5:e7:68:e3:56:37:92:b3:61:af:b0:
8a:ef
pub:
04:40:4c:98:c5:a8:4c:c9:4e:87:ee:2e:06:91:7d:
29:cc:eb:60:36:22:6b:c3:12:c6:4a:22:d2:80:18:
05:8d:5f:d5:7c:62:14:8e:b4:25:89:ae:be:28:f9:
50:25:dd:08:46:d4:0b:20:6d:24:a9:77:83:ff:2c:
9e:8a:4b:98:07
ASN1 OID: prime256v1
NIST CURVE: P-256
I'm working with a third party attempting to establish digital signature matching in both directions. On my side we are using C# while the third party is using Java. So far I am able to generate a key pairing within OpenSSL and use the private key to generate a signature which they are able to match in their Java environment (C# code below). Going the opposite direction, how do I use the generated public key to create a matching signature?
I've attempted using the same code below simply changing the CngKeyBlobFormat when importing the public key but all other types produce an error.
On both sides the following OpenSSL commands were used to generate the public and private keys:
openssl genrsa -des3 -out my_rsa_key_pair 2048
openssl pkcs8 -topk8 -inform PEM -in my_rsa_key_pair -outform PEM -out private_key.pem -nocrypt
openssl rsa -in my_rsa_key_pair -outform PEM -pubout -out public_key.pem
This is the C# code used to generate a signature from the private key:
byte[] keyBytes = Convert.FromBase64String(privateKey);
byte[] valueBytes = Encoding.UTF8.GetBytes(stringToSign);
byte[] signedBytes;
using (CngKey key = CngKey.Import(keyBytes, CngKeyBlobFormat.Pkcs8PrivateBlob))
using (RSA rsa = new RSACng(key))
{
signedBytes = rsa.SignData(valueBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signedBytes);
}
Using the public key I need to generate a signature within C# that matches what was generated with the private key. What is the proper way to do this?
There are a lot of posts surrounding signature generation / verification and after hitting on the right key words I found the answer in the following post. Given the above code and method of generating public/private key pairings the answer in this post will successfully validate the signature generated with a private key using only the public key. Leaving this open for anyone searching for both sides of the solution:
Verify signature generated with RSA 2048-bit key, SHA256 algorithm and PKCSv1.5 padding
I have an RSA private key loaded in an RSACryptoServiceProvider object. I need to export this to a .pvk file for use with SQL Server.
Is there a way to do this from within c#? I see it's possible using openssl... https://stackoverflow.com/a/51207929/5924962
This is the only documentation I could find on the pvk file format: https://web.archive.org/web/20141117214716/http://www.drh-consultancy.demon.co.uk/pvk.html
Mono project has an open source implementation of the PVK format,
https://github.com/mono/mono/blob/master/mcs/class/Mono.Security/Mono.Security.Authenticode/PrivateKey.cs
Note the Mono.Security NuGet package is not official.
If you look at the output of RSACryptoServiceProvider.ExportCspBlob you'll see that it starts with the same sequence of bytes as offset 24 of an unencrypted PVK file. So a PVK file is just the CSP blob with a header:
using (var output = new BinaryWriter(File.Create("rsa.pvk")))
{
output.Write(0xB0B5F11Eu); // PVK magic number
output.Write(0u);
output.Write(1u); // KEYTYPE_KEYX for RSA
output.Write(0u); // not encrypted
output.Write(0u); // encryption salt length
var cspBlob = rsaCSP.ExportCspBlob(true);
output.Write((uint)cspBlob.Length);
output.Write(cspBlob);
}
I've verified that OpenSSL will read this
openssl rsa -in rsa.pvk -inform PVK
and will generate the same PEM private key export as the code in this answer that generates the PEM private key directly from the RSACryptoServiceProvider.
This question already has answers here:
how to get private key from PEM file?
(7 answers)
Signing and verifying signatures with RSA C#
(1 answer)
Closed 5 years ago.
I want to sign some data with RSA.SignHash().
I've created a RSA private key file via the following command in Linux OpenSSL.
openssl genrsa -out private_key.pem 1024
But when I want to load this key by an object of X509Certificate2, get the "Cannot find the requested object." exception.
Here is my code:
string keyFilePath = #"C:\Keys\private_key.pem";
X509Certificate2 cert = new X509Certificate2(keyFilePath);
I've used the Chilkat library and everything works fine, But doesn't Microsoft have any walk-though to approach it without any third-party tools?
Here is my pem file content:
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQC23ivEPgSqxCcSTNUY8IbjCO0+0FwarI/azCHp97cWCBaosFAe
mN9eI7u3agv2tCk+QrKrFDlkYWskFiADm55NMvDE1fuyy7db84MMh+GFcyemYZ0o
yG5oBYPw7aNY7N7fBO5pbF9M/v4TMjKoxYGxk2kl58KT9cmvVH7TaF8xkwIDAQAB
AoGAfVzRpDbf/DF8l48Uh4Rc9EeqXOV6Ps8Nz3EhzsODQBdLcVltk4w5lM/qYFLS
4M2heI1A7wduUOJ4EMUaLV8BpcFkA2kSPah48R/1EGAMOpaD09j8qHJLCHJ2uiSc
Hqi6z/6GhpSLzU5XR1lj0UIPy9aC9X0yPAao0WZ+5YgTdAECQQDoCwCmFD5r00Y0
DcQGbAU/eekHJwNk48ACvIDquK/ysqA8aXvWgyXd3oa82fUSvSAMDGNFYr9xOxqF
Vnnsi6VXAkEAyb9yymbehjwwl33CjPcsIRbjetLDwPgWhVYii4q7jELlefyC8mHL
cpn0ejS4ln/uTUuNZCdYNHvYjQ8eXfaUJQJADfM7YsCs0AavncmGE2zDFAHcRJXP
2mzmykNS7MmVql2azIb67vaLfD84knn4Bdxg5NiJz04UfFY1TfbY9aOfmQJBAJGX
jsCQMiBPSYXZ5M+UBI2wleNqPIiCwMXinjVzndsf37kDyIAgoRCIGA0lBNzfX9r6
HgRb/GSLx4Asm+6VZt0CQQC2DwtG+CKDyqEvhIGqlrAuQivMLJExZZV3kjsFSWOA
CZFSr8JsSghb3bbxYexkzbWfalESYRkqu+zNWDPs9gpt
-----END RSA PRIVATE KEY-----
No, there is no friendly way to do it without third-party tools. If you only have private key then IMHO new X509Certificate2(keyFilePath) does not make sense.
What you could do is implement (or use a library) to parse the private key. Then encode parsed private key parameters to a xml structure that can be imported using RSA.FromXmlString.
I want to create .pem file for the public key generated by this method
public static Tuple<string, string> CreateKeyPair()
{
CspParameters cspParams =
new CspParameters {
ProviderType = 1 /* PROV_RSA_FULL */
};
RSACryptoServiceProvider rsaProvider =
new RSACryptoServiceProvider(1024, cspParams);
string publicKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(false));
string privateKey = Convert.ToBase64String(rsaProvider.ExportCspBlob(true));
return new Tuple<string, string>(privateKey, publicKey);
}
Because I was generating this key for mobile application and they can not read it, they requested .pem file instead of public key as string
Please advice,
Recently I need to save PublicKey and PrivateKey generated in my C# application to file, and works with it later. I use for this purpose such library as CSharp-easy-RSA-PEM.
It is very simple and quick solution, so I will recommend this library to other guys.
I use following code to get PublicKey as string (and save it to pem file in format Base64):
string publicKeyStr = Crypto.ExportPublicKeyToX509PEM(_cryptoServiceProvider);
it returns something like this:
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxnBvS8cdsnAev2sRDRYWxznm1
QxZzaypfNXLvK7CDGk8TR7K+Pzsa+tpJfoyN/Z4B6xdlpsERo2Cu6AzolvrDLx5w
ZoI0kgdfaBMbUkdOB1m97zFYjKWoPeTskFzWZ3GHcQ3EXT0NJXXFXAskY45vEpbc
5qFgEhcPy3BMqHRibwIDAQAB
-----END PUBLIC KEY-----
And I use following code to get PrivateKey as string:
string privateKeyStr = Crypto.ExportPrivateKeyToRSAPEM(_cryptoServiceProvider);
it returns something like this:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCxnBvS8cdsnAev2sRDRYWxznm1QxZzaypfNXLvK7CDGk8TR7K+
Pzsa+tpJfoyN/Z4B6xdlpsERo2Cu6AzolvrDLx5wZoI0kgdfaBMbUkdOB1m97zFY
jKWoPeTskFzWZ3GHcQ3EXT0NJXXFXAskY45vEpbc5qFgEhcPy3BMqHRibwIDAQAB
AoGAAdwpqm7fxh0S3jOYpJULeQ45gL11dGX7Pp4CWHYzq1vQ14SDtFxYfnLWwGLz
499zvSoSHP1pvjPgz6lxy9Rw8dUxCgvh8VQydMQzaug2XD1tkmtcSWInwFKBAfQ7
rceleyD0aK8JHJiuzM1p+yIJ/ImGK0Zk2U/svqrdJrNR4EkCQQDo3d5iWcjd3OLD
38k1GALEuN17KNpJqLvJcIEJl0pcHtOiNnyy2MR/XUghDpuxwhrhudB/TvX4tuI0
MUeVo5fjAkEAw0D6m9jkwE5uuEYN/l/84rbQ79p2I7r5Sk6zbMyBOvgl6CDlJyxY
434DDm6XW7c55ALrnlratEW5HPiPxuHZBQJANnE4vtGy7nvn4Fd/mRQmAYwe695f
On1iefP9lxpx3huu6uvGN6IKPqS2alQZ/nMdCc0Be+IgC6fmNsGWtNtsdQJAJvB4
ikgxJqD9t8ZQ2CAwgM5Q0OTSlsGdIdKcOeB3DVmbxbV5vdw8RfJFjcVEbkgWRYDH
mKcp4rXc+wgfNFyqOQJATZ1I5ER8AZAn5JMMH9zK+6oFvhLUgKyWO18W+dbcFrBd
AzlTB+HHYEIyTmaDtXWAwgBvJNIHk4BbM1meCH4QnA==
-----END RSA PRIVATE KEY-----
Then you can use
RSACryptoServiceProvider publicX509key = Crypto.DecodeX509PublicKey(publicKeyStr);
RSACryptoServiceProvider privateRSAkey = Crypto.DecodeRsaPrivateKey(privateKeyStr);
to restore saved keys back to RSACryptoServiceProvider.
So, if someone need to resolve similar issue, you can just download this library, go to Solution Explorer -> (Right click on your project) -> Add -> Reference -> Overview in your Visual Studio to add this library in your project, and add using CSharp_easy_RSA_PEM; where you need it :)
First off, a so-called .pem file is not really a fixed specification or format. Several different kinds of distinct file formats are generally described as "PEM" files. When the SSLeay (now OpenSSL) project needed to produce a base64 encoded output file containing key information they borrowed formatting concepts from the old Privacy-Enhanced Mail RFCs 1421-1424 and they added the extension .pem to the end of these files. But such a file may contain public keys, private keys, certificate requests, certificates, certificate lists, and so on. Each is different. So if all you're told is to produce a .pem file you're going to have to guess what's really needed.
The easiest way to write such files is to use the Bouncycastle C# library. The package Org.BouncyCastle.OpenSsl contains a number of utilities including a PemWriter class that should help you.