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

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));

Related

OpenPGP decryption in C# with X.509 Certificate .pfx file private key

Friends,
We procured class 3 certificate both .pfx and .cer certificates from Certificate Authority. And shared .cer(public key) to our partner.
Encryption (Java)
Our Partner encrypted the message (with our public key) using Java bouncy castle openpgp standard and shared the encrypted message like below,
-----BEGIN PGP MESSAGE-----
Version: x
v2hQEMAzFXJ94q1Nm8AQf/Tld0/3dAvgFKPQVBS8bmbXChXeApeReo1ydNS+......
-----END PGP MESSAGE-----
Decryption: (C#)
We need to decrypt the message with our .pfx file.
I have gone through below articles,
http://burnignorance.com/c-coding-tips/pgp-encryption-decryption-in-c/
It seems new PGPKeyPair is being generated and used for encryption and decryption.
But in my case, i have .pfx file
How do we extract the pgpprivate key from .pfx file use for decryption?
Could you share some thoughts on how we can do this. Advance thanks for all your time on this.
13/12/2020
I had imported the X509Certificate .pfx into store like below and trying to convert the pgpprivate key,
string certPath = #"C:\Users\test.pfx";
string certPass = "apples";
// Create a collection object and populate it using the PFX file
X509Certificate2Collection collection = new X509Certificate2Collection();
collection.Import(certPath, certPass, X509KeyStorageFlags.PersistKeySet);
X509Certificate2 certificate = collection[0];
AsymmetricAlgorithm x509PrivateKey = certificate.PrivateKey;
PgpPrivateKey pK = x509PrivateKey; //Here i am gettting the invalid conversion error.
I am trying to use the X.509 certificate Private key as PGPrivatekey in decryption. But while assigning the private key to pgpprivatekey, getting the invalid cast exception.
Is there any way to achive this?
Regards,
Stalin
You can try using BouncyCastle API to read pfx file using PKCS12 class file, then convert the key to PgpSecretKey.
read document on -- > pkcs12.GetKey()
and PgpSecretKey class.
public static void GetPriveKey(String pfxFile, String pfxPassword)
{
//Load PKCS12 file
Pkcs12Store pkcs12 = new Pkcs12Store(new FileStream(pfxFile, FileMode.Open, FileAccess.Read), pfxPassword.ToArray());
string keyAlias = null;
foreach (string name in pkcs12.Aliases)
{
if (pkcs12.IsKeyEntry(name))
{
keyAlias = name;
break;
}
}
//
AsymmetricKeyParameter Privatekey = pkcs12.GetKey(keyAlias).Key;
X509CertificateEntry[] ce = pkcs12.GetCertificateChain(keyAlias);
AsymmetricKeyParameter PublicKey= ce[0].Certificate.GetPublicKey();
PgpSecretKey mySecretKey = new PgpSecretKey(PgpSignature.DefaultCertification,
PublicKeyAlgorithmTag.RsaGeneral,
PublicKey,
Privatekey,
DateTime.UtcNow,
keyAlias,
SymmetricKeyAlgorithmTag.Cast5,
pfxPassword.ToCharArray(),
true,
null,
null,
new SecureRandom());
}

Is the KeyStore encrypted by default?

I currently have some code that stores my sensitive information in the KeyStore like so:
static readonly char[] Password = null;
//Create KeyStore
ks = KeyStore.GetInstance(KeyStore.DefaultType);
prot = new KeyStore.PasswordProtection(Password);
//AddUserName
var alias = MakeAlias("UserName", serviceId);
var usernameSecretKey = new SecretAccount(username);
var usernameEntry = new KeyStore.SecretKeyEntry(usernameSecretKey);
ks.SetEntry(alias, usernameEntry, prot);
now this has got PasswordProtection but the password is null.
Pulling my Keystore file off the device I can see the data is encrypted (not in plain text). But is this data encrypted enough or is it simple by decrypting by calling something like File.Decrypty(password = null);
Keystore is not encrypted by default but it contains the encrypted key information with it, which is password protected
https://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.html

RSA public key to base 64

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

CryptographicException "Key not valid for use in specified state." while trying to export RSAParameters of a X509 private key

I am staring at this for quite a while and thanks to the MSDN documentation I cannot really figure out what's going. Basically I am loading a PFX file from the disc into a X509Certificate2 and trying to encrypt a string using the public key and decrypt using the private key.
Why am I puzzled: the encryption/decryption works when I pass the reference to the RSACryptoServiceProvider itself:
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
But if the export and pass around the RSAParameter:
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
...it throws a "Key not valid for use in specified state." exception while trying to export the private key to RSAParameter. Please note that the cert the PFX is generated from is marked exportable (i.e. I used the pe flag while creating the cert). Any idea what is causing the exception?
static void Main(string[] args)
{
X509Certificate2 x = new X509Certificate2(#"C:\temp\certs\1\test.pfx", "test");
x.FriendlyName = "My test Cert";
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
try
{
store.Add(x);
}
finally
{
store.Close();
}
byte[] ed1 = EncryptRSA("foo1", x.PublicKey.Key as RSACryptoServiceProvider);
string foo1 = DecryptRSA(ed1, x.PrivateKey as RSACryptoServiceProvider);
byte[] ed = EncryptRSA("foo", (x.PublicKey.Key as RSACryptoServiceProvider).ExportParameters(false));
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider).ExportParameters(true));
}
private static byte[] EncryptRSA(string data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
RSACryptoServiceProvider publicKey = new RSACryptoServiceProvider();
publicKey.ImportParameters(rsaParameters);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSAParameters rsaParameters)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
RSACryptoServiceProvider privateKey = new RSACryptoServiceProvider();
privateKey.ImportParameters(rsaParameters);
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
private static byte[] EncryptRSA(string data, RSACryptoServiceProvider publicKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] plainData = bytConvertor.GetBytes(data);
return publicKey.Encrypt(plainData, true);
}
private static string DecryptRSA(byte[] data, RSACryptoServiceProvider privateKey)
{
UnicodeEncoding bytConvertor = new UnicodeEncoding();
byte[] deData = privateKey.Decrypt(data, true);
return bytConvertor.GetString(deData);
}
Just to clarify in the code above the bold part is throwing:
string foo = DecryptRSA(ed, (x.PrivateKey as RSACryptoServiceProvider)**.ExportParameters(true)**);
I believe that the issue may be that the key is not marked as exportable. There is another constructor for X509Certificate2 that takes an X509KeyStorageFlags enum. Try replacing the line:
X509Certificate2 x = new X509Certificate2(#"C:\temp\certs\1\test.pfx", "test");
With this:
X509Certificate2 x = new X509Certificate2(#"C:\temp\certs\1\test.pfx", "test", X509KeyStorageFlags.Exportable);
For the issue I encountered a code change was not an option as the same library was installed and working elsewhere.
Iridium's answer lead me to look making the key exportable and I was able to this as part of the MMC Certificate Import Wizard.
Hope this helps someone else. Thanks heaps
I've met some similar issue, and X509KeyStorageFlags.Exportable solved my problem.
I'm not exactly an expert in these things, but I did a quick google, and found this:
http://social.msdn.microsoft.com/Forums/en/clr/thread/4e3ada0a-bcaf-4c67-bdef-a6b15f5bfdce
"if you have more than 245 bytes in your byte array that you pass to your RSACryptoServiceProvider.Encrypt(byte[] rgb, bool fOAEP) method then it will throw an exception."
For others that end up here through Google, but don't use any X509Certificate2, if you call ToXmlString on RSACryptoServiceProvider but you've only loaded a public key, you will get this message as well. The fix is this (note the last line):
var rsaAlg = new RSACryptoServiceProvider();
rsaAlg.ImportParameters(rsaParameters);
var xml = rsaAlg.ToXmlString(!rsaAlg.PublicOnly);
AFAIK this should work and you're likely hitting a bug/some limitations. Here's some questions that may help you figure out where's the issue.
How did you create the PKCS#12 (PFX) file ? I've seen some keys that CryptoAPI does not like (uncommon RSA parameters). Can you use another tool (just to be sure) ?
Can you export the PrivateKey instance to XML, e.g. ToXmlString(true), then load (import) it back this way ?
Old versions of the framework had some issues when importing a key that was a different size than the current instance (default to 1024 bits). What's the size of your RSA public key in your certificate ?
Also note that this is not how you should encrypt data using RSA. The size of the raw encryption is limited wrt the public key being used. Looping over this limit would only give you really bad performance.
The trick is to use a symmetric algorithm (like AES) with a totally random key and then encrypt this key (wrap) using the RSA public key. You can find C# code to do so in my old blog entry on the subject.
Old post, but maybe can help someone.
If you are using a self signed certificate and make the login with a different user, you have to delete the old certificate from storage and then recreate it. I've had the same issue with opc ua software

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) {

Categories

Resources