I have a problem when I try to decrypt a string generated using RSA in C#. It Encrypts the strings well, but it throws an error when I try to decrypt the string using the private key:
Error occurred while decoding OAEP padding.
I tried changing the fOAEP parameter between true and false, changing the RSACryptoServiceProviders with 2048 as parameter and still doesn't work.
Project is a WPF App which generates 2 files with the keys, keys are loaded by the core.cs file. Then keys are being loaded.
The example I taken only uses the public key to encrypt the string and only the private key to decrypt the string.
Core.cs File
// Keys are generated
public void GeneratePublicKey(string publicKeyFile) {
using (var rsa = new RSACryptoServiceProvider(2048)) {
rsa.PersistKeyInCsp = false;
if (File.Exists(publicKeyFile))
File.Delete(publicKeyFile);
//and the public key ...
var pubKey = rsa.ExportParameters(false);
//converting the public key into a string representation
string pubKeyString; {
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, pubKey);
//get the string from the stream
pubKeyString = sw.ToString();
}
File.WriteAllText(publicKeyFile, pubKeyString);
}
}
public void GeneratePrivateKey(string privateKeyFile) {
using (var rsa = new RSACryptoServiceProvider(2048)) {
rsa.PersistKeyInCsp = false;
if (File.Exists(privateKeyFile))
File.Delete(privateKeyFile);
//how to get the private key
var privKey = rsa.ExportParameters(true);
//converting the public key into a string representation
string privKeyString;
{
//we need some buffer
var sw = new System.IO.StringWriter();
//we need a serializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//serialize the key into the stream
xs.Serialize(sw, privKey);
//get the string from the stream
privKeyString = sw.ToString();
}
File.WriteAllText(privateKeyFile, privKeyString);
}
}
//Si las llaves ya existen entonces NO Generar, solo leer la llave indicada (leer el texto de la ruta)
public RSAParameters ReadPublicKey(string publicKeyFile) {
//Leer
string pubKeyString = File.ReadAllText(publicKeyFile);
//Reconvertir
var sr = new System.IO.StringReader(pubKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
return (RSAParameters)xs.Deserialize(sr);
}
public RSAParameters ReadPrivateKey(string privateKeyFile) {
//Leer
string privKeyString = File.ReadAllText(privateKeyFile);
//Reconvertir
var sr = new System.IO.StringReader(privKeyString);
//we need a deserializer
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
//get the object back from the stream
return (RSAParameters)xs.Deserialize(sr);
}
//Con la llave publica se encripta el texto
public string Encrypt(string publicKeyFile, string textToEncrypt) {
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(ReadPublicKey(publicKeyFile));
//for encryption, always handle bytes...
var bytesPlainTextData = System.Text.Encoding.Unicode.GetBytes(textToEncrypt);
//apply pkcs#1.5 padding and encrypt our data
var bytesCypherText = csp.Encrypt(bytesPlainTextData, true);
//we might want a string representation of our cypher text... base64 will do
Debug.WriteLine("Texto Encriptado: "+Convert.ToBase64String(bytesCypherText));
return Convert.ToBase64String(bytesCypherText);
}
/// <summary>
/// Con la llave Privada se Desencripta
/// </summary>
/// <param name="privateKeyFile"></param>
/// <param name="textToDecrypt"></param>
/// <returns></returns>
public string Decrypt(string privateKeyFile, string textToDecrypt) {
//first, get our bytes back from the base64 string ...
var bytesCypherText = Convert.FromBase64String(textToDecrypt);
//we want to decrypt, therefore we need a csp and load our private key
var csp = new RSACryptoServiceProvider();
csp.ImportParameters(ReadPrivateKey(privateKeyFile));
//decrypt and strip pkcs#1.5 padding
var bytesPlainTextData = csp.Decrypt(bytesCypherText, true);
Debug.WriteLine("Desencriptado: "+
System.Text.Encoding.Unicode.GetString(bytesPlainTextData));
//get our original plainText back...
return System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
}
MainWindow.cs
public partial class MainWindow : Window {
readonly RsaEnc _rs = new RsaEnc();
private string _publicKeyFile = "./public.cert";
private string _privateKeyFile = "./private.key";
public MainWindow() {
InitializeComponent();
}
private void GenerateBtn_Click(object sender, RoutedEventArgs e) {
_rs.GeneratePublicKey(_publicKeyFile);
_rs.GeneratePrivateKey(_privateKeyFile);
}
private void OpenPublic_Click(object sender, RoutedEventArgs e) {
OpenFileDialog fileDialog = new OpenFileDialog {
Multiselect = false, Filter = "Public |*.cert", DefaultExt = ".cert"
};
bool? dialogOk = fileDialog.ShowDialog();
if (dialogOk == true) {
string sFilenames = "";
foreach (string sFileName in fileDialog.FileNames) {
sFilenames += ";" + sFileName;
}
sFilenames = sFilenames.Substring(1);
_publicKeyFile = sFilenames;//Esto solo da la RUTA
Debug.WriteLine("public Cert: " + _publicKeyFile);
}
}
private void OpenPrivate_Click(object sender, RoutedEventArgs e) {
OpenFileDialog fileDialog = new OpenFileDialog
{
Multiselect = false, Filter = "Certificates |*.key", DefaultExt = ".key"
};
bool? dialogOk = fileDialog.ShowDialog();
if (dialogOk == true) {
string sFilenames = "";
foreach (string sFileName in fileDialog.FileNames) {
sFilenames += ";" + sFileName;
}
sFilenames = sFilenames.Substring(1);
_privateKeyFile = sFilenames; //Esto solo da la RUTA
Debug.WriteLine("private Key: " + _privateKeyFile);
}
}
private void EncryptBtn_Click(object sender, RoutedEventArgs e) {
_rs.Encrypt(_publicKeyFile, BoxToEncrypt.Text);
}
private void DecryptBtn_Click(object sender, RoutedEventArgs e) {
_rs.Decrypt(_privateKeyFile, BoxToDecrypt.Text);
}
}