C#/WPF RSA 不解密文本
C# / WPF RSA Doesn't Decrypt Text
当我尝试解密在 C# 中使用 RSA 生成的字符串时遇到问题。它很好地加密了字符串,但是当我尝试使用私钥解密字符串时它会抛出错误:
Error occurred while decoding OAEP padding.
我尝试在 true 和 false 之间更改 fOAEP 参数,将 RSACryptoServiceProviders 更改为 2048 作为参数,但仍然不起作用。
项目是一个 WPF 应用程序,它使用密钥生成 2 个文件,密钥由 core.cs 文件加载。
然后正在加载密钥。
我举的例子只用public密钥加密字符串,只用私钥解密字符串。
Core.cs 文件
// 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);
}
}
RSA 密钥总是成对生成的,一个 public 和一个私有密钥。这些键是在 RSACryptoServiceProvider
的构造函数中创建的。您的代码在 GeneratePublicKey
和 GeneratePrivateKey
中调用此构造函数,因此将生成两个不相关的密钥对。
你应该可以检查这个。导出参数时,始终包含 public 组件。如果它们不相同,那将作为确认。
修复方法是同时生成 public 和私钥。
首先,WPF 和解密是两个不同的东西。因此,我们必须只关注 RSA encrypt/decrypt 部分。
在您的代码中,您尝试使用不同的方法生成 public/private 密钥。一个单独的 rsaprovider 应该导出两个参数。我提供了使用 RSA encryption/decryption 的示例代码。请检查以下内容。
internal sealed class RSA
{
public static (string public_key, string private_key) getKeyPair()
{
try
{
var rsa_provider = new RSACryptoServiceProvider(1024);
return (rsa_provider.ToXmlString(false), rsa_provider.ToXmlString(true));
}
catch (Exception ex)
{
throw ex;
}
}
public static byte[] shroud_divulge(byte[] input_byte, string _key,bool is_shroud)
{
try
{
var rsa_provider = new RSACryptoServiceProvider();
rsa_provider.FromXmlString(_key);
var padding = RSAEncryptionPadding.OaepSHA256;
switch(is_shroud)
{
case true:
return rsa_provider.Encrypt(input_byte, padding);
case false:
return rsa_provider.Decrypt(input_byte, padding);
}
return null;
}
catch (Exception)
{
throw;
}
}
}
它有两个简单的方法和 returns 使用 valuetuple 输出(所以添加 Valutuple nuget 包)。
文件保存和处理是在 RSA 逻辑之外完成的。裹尸布 - 加密,泄露 - 解密。 (请原谅使用的命名约定,这是按照我们公司的标准)。
我们通常随 WPF 应用程序一起提供公钥。
为了加密(Shroud),我们传入私钥..
对于解密(Divulge),我们传入公钥..
当我尝试解密在 C# 中使用 RSA 生成的字符串时遇到问题。它很好地加密了字符串,但是当我尝试使用私钥解密字符串时它会抛出错误:
Error occurred while decoding OAEP padding.
我尝试在 true 和 false 之间更改 fOAEP 参数,将 RSACryptoServiceProviders 更改为 2048 作为参数,但仍然不起作用。
项目是一个 WPF 应用程序,它使用密钥生成 2 个文件,密钥由 core.cs 文件加载。 然后正在加载密钥。
我举的例子只用public密钥加密字符串,只用私钥解密字符串。
Core.cs 文件
// 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);
}
}
RSA 密钥总是成对生成的,一个 public 和一个私有密钥。这些键是在 RSACryptoServiceProvider
的构造函数中创建的。您的代码在 GeneratePublicKey
和 GeneratePrivateKey
中调用此构造函数,因此将生成两个不相关的密钥对。
你应该可以检查这个。导出参数时,始终包含 public 组件。如果它们不相同,那将作为确认。
修复方法是同时生成 public 和私钥。
首先,WPF 和解密是两个不同的东西。因此,我们必须只关注 RSA encrypt/decrypt 部分。
在您的代码中,您尝试使用不同的方法生成 public/private 密钥。一个单独的 rsaprovider 应该导出两个参数。我提供了使用 RSA encryption/decryption 的示例代码。请检查以下内容。
internal sealed class RSA
{
public static (string public_key, string private_key) getKeyPair()
{
try
{
var rsa_provider = new RSACryptoServiceProvider(1024);
return (rsa_provider.ToXmlString(false), rsa_provider.ToXmlString(true));
}
catch (Exception ex)
{
throw ex;
}
}
public static byte[] shroud_divulge(byte[] input_byte, string _key,bool is_shroud)
{
try
{
var rsa_provider = new RSACryptoServiceProvider();
rsa_provider.FromXmlString(_key);
var padding = RSAEncryptionPadding.OaepSHA256;
switch(is_shroud)
{
case true:
return rsa_provider.Encrypt(input_byte, padding);
case false:
return rsa_provider.Decrypt(input_byte, padding);
}
return null;
}
catch (Exception)
{
throw;
}
}
}
它有两个简单的方法和 returns 使用 valuetuple 输出(所以添加 Valutuple nuget 包)。 文件保存和处理是在 RSA 逻辑之外完成的。裹尸布 - 加密,泄露 - 解密。 (请原谅使用的命名约定,这是按照我们公司的标准)。
我们通常随 WPF 应用程序一起提供公钥。 为了加密(Shroud),我们传入私钥.. 对于解密(Divulge),我们传入公钥..