How to read der file and convert to AsymmetricCipherKeyPair? - c#

I have a der file 'text.der' that contains a DER-encoded key. I want read it and convert to an instance of AsymmetricCipherKeyPair from the Bouncycastle C# library (here are the javadocs for the Java version).
For example for a pem file, we have PemReader/Writer in bouncycastle and we can do it.
How can I go from the encoded key in a file to an AsymmetricCipherKeyPair

Assuming its the usual binary format DER public key file, with the binary DER coding for the SubjectPublicKeyInfo structure (I think OpenSSL uses this for its DER output format), you can do:
byte[] derKeyBytes = File.ReadAllBytes("text.der"); // read in the binary file
// Decode the public key component
AsymmetricKeyParameter publicKey =
PublicKeyFactory.CreateKey(derKeyBytes);
You're better of just using the AsymmetricKeyParameter (which is the public part of the key), but if you absolutely want it in a AsymmetricCipherKeyPair, you can do this:
// Put the public key into a keyPair, leave the Private key uninitialized.
AsymmetricCipherKeyPair keyPair =
new AsymmetricCipherKeyPair(
publicKey,
new AsymmetricKeyParameter(true));

Related

Bouncy Castle C# - PrivateKeyFactory.CreateKey 'Unknown object in GetInstance'

I have a sample C# script that handle decryption. By using the key provided with the sample, the code is working fine:
public static string DecryptByPrivateKey(string s, string key)
{
s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
engine.Init(false, GetPrivateKeyParameter(key));
byte[] byteData = Convert.FromBase64String(s);
var resultData = engine.ProcessBlock(byteData, 0, byteData.Length);
return CommonHelper.EncodeBase64(resultData);
}
private static AsymmetricKeyParameter GetPrivateKeyParameter(string s)
{
s = s.Replace("\r", "").Replace("\n", "").Replace(" ", "");
byte[] privateInfoByte = Convert.FromBase64String(s);
AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(privateInfoByte);
return priKey;
}
However, when using our own private key, above function will throw exception at PrivateKeyFactory.CreateKey():
System.ArgumentException: 'Unknown object in GetInstance:
Org.BouncyCastle.Asn1.DerInteger Parameter name: obj'
Our public/private key strings are generated with openssl on windows with command line:
openssl pkcs12 -in cert.pfx -nocerts -nodes -out cert.key
openssl rsa -in cert.key -out cert_private.key
openssl rsa -in cert.key -pubout -out cert_public.key
The key strings are in base64 format. The sample private key have 1624 characters while our private key has 1592 only.
In Visual Studio debug mode I checked the parameter privateInfoByte is a "byte[1192]". I have no clue on the error.
I am not sure my key strings are in correct format. How can I verify? Thank you.
According to the documentation, PrivateKeyFactory.CreateKey() expects a private key in PKCS#8 format. However, cert_private.key has the PKCS#1 format, which is thus incompatible.
cert.key, on the other hand, contains among other things the private key in PKCS#8 format, which can be extracted from this. Alternatively, the PKCS#1 formatted key can be converted to a PKCS#8 formatted key using OpenSSL, see openssl pkcs8:
openssl pkcs8 -topk8 -nocrypt -in <pkcs#1 key file> -out <pkcs#8 key file>
cert_private.key and cert.key contain the PEM encoded keys consisting of header, footer and the Base64 encoding of the DER encoded keys.
PrivateKeyFactory.CreateKey() expects a DER encoded key, i.e. from the PEM encoded key determined e.g. from cert.key, header, footer and line breaks are to be removed and the rest has to be Base64 decoded (which seems to be already considered in your code).
Header/footer of the PEM encoded PKCS#8 key are -----BEGIN PRIVATE KEY-----/-----END PRIVATE KEY----- and of the PEM encoded PKCS#1 key -----BEGIN RSA PRIVATE KEY----- / -----END RSA PRIVATE KEY-----.
Edit:
The statement openssl pkcs12 -out... -in... parses a PKCS#12 file and writes the contained certificates and private keys PEM encoded to a file. -nocerts causes the contained certificates not to be written, -nodes causes the private keys not to be encrypted (i.e. your statement exports only the PEM encoded private key unencrypted). The format of the exported private key is not explicitly specified, but can be easily identified as PKCS#8 using header/footer or an ASN.1 parser.
The statement openssl rsa -in... -out... finally exports the PKCS#8 formatted key to a PKCS#1 formatted key (PEM encoded). So to get the needed PKCS#8 formatted key you have the option to 1st use the PKCS#8 formatted key exported directly from the PKCS#12 file (s. previous section) or 2nd convert the PKCS#1 formatted key back to a PKCS#8 formatted key.
Therefore: yes, cert.pfx is a file in PKCS#12 format, and yes, cert_private.key is a key in PKCS#1 format, which is incompatible with PrivateKeyFactory.CreateKey(), which requires a key in PKCS#8 format.

Export RSA Public Key in DER Format and decrypt data

I need to get the bytes of my RSA Public Key in the DER format and send this key to an API. This API will then send me something encrypted using this Public Key back and i need to decrypt it.
First problem, it seems that C# doesn't have the ability to export RSA Keys in the DER Format. So it seems i have to rely on a 3rd party package like BouncyCastle. I also found a way to generate and export my Public Key in the DER Format with this package:
var generator = new RsaKeyPairGenerator();
generator.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
var keyPair = generator.GenerateKeyPair();
var publicKeyParam = (RsaKeyParameters)keyPair.Public;
var publicKey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKeyParam).GetDerEncoded();
So now i only had to Base64 encode those bytes and send it to the API and the API is happy. But now i'm stuck trying to figure out how i can decrypt the dat i received. First of all i decoded the base64 string and now i'm stuck with the bytes of the data. I can get the private key from the BouncyCastle "thing", but i cant seem to convert it to RsaCryptoServiceProvider correctly and the BouncyCastle documentation is kind of weird.
If anyone has an idea or another approach i would be more than happy.
Based on the comments i came up with this solution:
var rsa = new RSACryptoServiceProvider(2048); // my rsa to decrypt and encrypt data
var publicKeyParam = DotNetUtilities.GetRsaPublicKey(rsa.ExportParameters(false));
var publicKey = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKeyParam).GetDerEncoded(); // my exported public key in DER format
Thanks alot James K Polk!

Get private key file with sha256 in C #

Currently I perform this operation through openssl, and I have had no problem with the generated file
openssl dgst -sha256 -sign privateKey.key -out file.txt.signature file.txt
Now, we want to automate the generation of the file using C #, but I have not been able to get the same result.
public class Program
{
static void Main(string[] args)
{
Console.WriteLine(CreateToken("key...", "text"));
Console.ReadLine();
}
public static string CreateToken(string key, string message)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha256 = new HMACSHA256(keyByte);
byte[] messageBytes = encoding.GetBytes(message);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return System.Text.Encoding.UTF8.GetString(hashmessage);
}
}
I'm new to working with this, what would be the right way?
Am I not retrieving the information properly ?, Should I get the content directly from the file?
Thank you very much.
Signature generation is not the same thing as HMAC message authentication and it uses a different key. As HMAC can use a key of any size, it will probably take the private key, but that's not how it is supposed to work. RSA is an asymmetric algorithm that uses private and public keys, MAC uses symmetric, secret keys. The dgst -sign instead uses RSA PKCS#1 v1.5 padding to sign the file.
From the OpenSSL Wiki on dgst:
When signing a file, dgst will automatically determine the algorithm (RSA, ECC, etc) to use for signing based on the private key's ASN.1 info. When verifying signatures, it only handles the RSA, DSA, or ECDSA signature itself, not the related data to identify the signer and algorithm used in formats such as x.509, CMS, and S/MIME.
HMAC is not the same thing as SHA-256 either. RSA signature generation uses a hash, not a HMAC. You should use the SHA256 class to create a hash. HMAC is a message authentication code build using the SHA-256 hash. However, the SHA class is not needed as signature generation usually includes the hash generation (you sign a message, not a hash value).
So to create a signature, take a look at the RSAPKCS1SignatureFormatter class, it includes an example at the bottom. Try again using this example.
Make sure your message only contains ASCII (both in the text file as in your string) or your result may fail as well.

Encrypting Data with RSA in .NET

I have a DER file with sha1RSA as the Signature Algorithm. I have to encrypt some data using it.
Can anyone tell me how do I load the DER file and use the RSA public key in it to encrypt my data in .NET?
DER or Distinguished Encoding Rules is a method for encoding a data object, such as an X.509 certificate, to be digitally signed or to have its signature verified.
The X.509 certificate only contains the public key. You need the private key to decrypt!
Typically private keys are exchanged in .PFX files, which are password protected.
-- EDIT --
Sorry I misread your question. Yes, you can encrypt with the public key of X.509 certificate. You can load the .der by using System.Security.Cryptography.X509Certificates.X509Certificate2.Import method.
Then convert the public and encrypt, something like:
rsa = (RSACryptoServiceProvider) certificate.PublicKey.Key;
encryptedText = rsa.Encrypt(msg, true);

How to import RSA key from KEY file

I need to encrypt string in my app using RSA key from file .key.
It contains something like this:
---BEGIN RSA PRIVAET KEY---
MIICHATIABBgQDi+.....OKh4=
---END RSA PRIVATE KEY---
So, I know that I can use RSACryptoServiceProvider class to encrypt my string, but how can I import key from .key file?
You can use the Bouncycastle C# crypto library, specifically the PEMReader class. PEMReader.readObject() will read it in and return an AsymmetricCipherKeyPair containing the private and public keys. You can then use the DotNetUtilities class to convert to .NET objects.

Categories

Resources