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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With