I'm currently attempting to build a system which encrypts customer data and adds it to a remote MSMQ queue which is on another server. The data is then picked up by a job that runs every X Minute which will attempt to decrypt the data and processes it.
There is a requirement of us having to use .PFX Certificate to do the encryption/decryption (which I am aware is not be most efficient way of doing things but the requirement is there and I am unable to get this changed).
I am currently using a self-signed certificate using Open-SSL using:
openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem
openssl pkcs12 -inkey key.pem -in certificate.pem -export -out certificate.p12
I have been successful at encrypting the data but every time I attempt a decrypt, I get the generic "The parameter is incorrect" exception.
To load the certificate, we have the .PFX file saved locally on the machines and using the X509Certificate2 class, we import it and use it to encrypt and decrypt. Here is a simplified version of the helper class that I am working with:
public static string EncryptData(string data)
{
var certificate = GetCertificate();
using (var rsa = certificate.PublicKey.Key as RSACryptoServiceProvider)
{
var dataBytes = Convert.FromBase64String(data);
var encryptedBytes = rsa.Encrypt(dataBytes, false);
return Convert.ToBase64String(encryptedBytes);
}
}
public static string DecryptData(string data)
{
var certificate = GetCertificate();
using (var rsa = certificate.PrivateKey as RSACryptoServiceProvider)
{
var dataBytes = Convert.FromBase64String(data);
var decryptedBytes = rsa.Decrypt(dataBytes, false);
return Convert.ToBase64String(decryptedBytes);
}
}
private static X509Certificate2 GetCertificate()
{
var certificate = new X509Certificate2();
certificate.Import("certificatePath", "certificatePassword", X509KeyStorageFlags.PersistKeySet);
return certificate;
}
The error always occurs on the "rsa.Decrypt()" call.
I have attempted the following:
Call "rsa.Decrypt()" in my "EncryptData" method right after encryption. This works with no issue and the "rsa.Decrypt" gives the me same bytes as the original data bytes.
Call "DecryptData" method straight after "EncryptData" call. The same issue occurs and I get Exception with "The parameter is incorrect"
This is why I suspect the fact a "new" X509Certificate2 is created that the private key is no longer the same and can no longer decrypt the data.
Please note that I am no security expert and have not worked with X509 Certificates or any cryptography for that matter so I am a bit out of my depth and may be doing something really silly so please let me know if I am.
Update 1 (08/03/2019)
Have updated the code code as per recommendation points 1-3 & 5 given by @bartonjs
public static string EncryptData(string data)
{
var certificate = GetCertificate();
using (var rsa = certificate.GetRSAPublicKey())
{
var dataBytes = Convert.FromBase64String(data);
var encryptedBytes = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA1);
return Convert.ToBase64String(encryptedBytes);
}
}
public static string DecryptData(string data)
{
var certificate = GetCertificate();
using (var rsa = certificate.GetRSAPrivateKey())
{
var dataBytes = Convert.FromBase64String(data);
var decryptedBytes = rsa.Decrypt(dataBytes, RSAEncryptionPadding.OaepSHA1);
return Convert.ToBase64String(decryptedBytes);
}
}
private static X509Certificate2 GetCertificate()
{
var certificate = new X509Certificate2("certificatePath", "certificatePassword", X509KeyStorageFlags.PersistKeySet);
return certificate;
}
Added error message:
Message: The parameter is incorrect.
Stack Trace:
at System.Security.Cryptography.NCryptNative.DecryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptDecryptor`1 decryptor)
at System.Security.Cryptography.NCryptNative.DecryptDataOaep(SafeNCryptKeyHandle key, Byte[] data, String hashAlgorithm)
at System.Security.Cryptography.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding)