[英]Bad data exception when decrypting using RSA with correct private and public key pair in C#
This is my code for decryption process: 这是我的解密过程代码:
private RSACryptoServiceProvider _rsa;
private string _privateKey;
private string _publicKey;
public RsaLibrary()
{
//initialsing the RSA object taking the option of a 1024 key size
_rsa = new RSACryptoServiceProvider(1024);
_privateKey = _rsa.ToXmlString(true);
_publicKey = _rsa.ToXmlString(false);
}
public string Decrypt(string ciphertext, string privateKey_ = null)
{
if (String.IsNullOrEmpty(privateKey_))
{
return DecryptToBytes(ciphertext, _privateKey);
}
else
{
return DecryptToBytes(ciphertext, privateKey_);
}
}
private string DecryptToBytes(string ciphertext, string privateKey)
{
if (String.IsNullOrEmpty(privateKey))
{
throw new ArgumentNullException("Error: No key provided.");
}
if (ciphertext.Length<=0)
{
throw new ArgumentNullException("Error: No message to decrypt.");
}
byte[] plaintext;
byte[] ciphertext_Bytes = Encoding.Unicode.GetBytes(ciphertext);
_rsa.FromXmlString(privateKey);
plaintext = _rsa.Decrypt(ciphertext_Bytes, false);
return Encoding.Unicode.GetString(plaintext);
}
The encryption code: 加密代码:
private string EncryptToByte(string plaintext, string publicKey)
{
if (String.IsNullOrEmpty(publicKey))
{
throw new ArgumentNullException("Error: No key provided.");
}
if (plaintext.Length<=0)
{
throw new ArgumentNullException("Error: No message to incrypt");
}
byte[] ciphertext;
byte[] plaintext_Bytes = Encoding.Unicode.GetBytes(plaintext);
_rsa.FromXmlString(publicKey);
ciphertext = _rsa.Encrypt(plaintext_Bytes, false);
return Convert.ToBase64String(ciphertext);
}
I can not see where I am going wrong. 我看不到我要去哪里错了。 I have made sure that the keys are correct. 我已确保密钥正确。 The public one which i extracted using this line in the constructor: _publicKey = _rsa.ToXmlString(false); 我在构造函数中使用此行提取的公共代码:_publicKey = _rsa.ToXmlString(false); This public key is displayed on the form that I created. 此公共密钥显示在我创建的表单上。 The private i used the "true" instead of false. 私人我使用“ true”代替false。
Any ideas? 有任何想法吗?
Ciphertext is very unlikely to be genuinely UTF-16-encoded text. 密文不太可能是真正的UTF-16编码文本。 Assuming that the encryption side had something like: 假设加密端具有以下内容:
string encryptedText = Encoding.Unicode.GetString(encryptedBytes);
you've basically lost data. 您基本上已经丢失了数据。 The result of encryption is not text - it's arbitrary binary data. 加密的结果不是文本-它是任意二进制数据。 If you want to convert that to text for some transport reason, you should use Base64, eg 如果出于某种运输原因要将其转换为文本,则应使用Base64,例如
string base64EncryptedText = Convert.ToBase64String(encryptedBytes);
Then use Convert.FromBase64String
to recover the original encrypted binary data which is ready to decrypt. 然后使用Convert.FromBase64String
恢复准备解密的原始加密二进制数据。
Here is your RsaLibrary
class using a base-64 string as Jon suggested: 这是Jon建议的使用base-64字符串的RsaLibrary
类:
class RsaLibrary
{
//initializing the RSA object taking the option of a 1024 key size
readonly RSACryptoServiceProvider _rsa = new RSACryptoServiceProvider(1024);
readonly string _privateKey;
readonly string _publicKey;
public RsaLibrary()
{
_privateKey = _rsa.ToXmlString(true);
_publicKey = _rsa.ToXmlString(false);
}
public string Decrypt(string ciphertext, string privateKey_ = null)
{
if (ciphertext.Length <= 0) throw new ArgumentNullException("ciphertext");
string key = String.IsNullOrEmpty(privateKey_) ? _privateKey : privateKey_;
return DecryptToBytes(ciphertext, key);
}
private string DecryptToBytes(string ciphertext, string privateKey)
{
if (String.IsNullOrEmpty(privateKey)) throw new ArgumentNullException("privateKey");
byte[] ciphertext_Bytes = Convert.FromBase64String(ciphertext);
_rsa.FromXmlString(privateKey);
byte[] plaintext = _rsa.Decrypt(ciphertext_Bytes, false);
return Encoding.Unicode.GetString(plaintext);
}
public string Encrypt(string plaintext, string publicKey_ = null)
{
if (plaintext.Length <= 0) throw new ArgumentNullException("plaintext");
string key = String.IsNullOrEmpty(publicKey_) ? _publicKey : publicKey_;
return EncryptToBytes(plaintext, key);
}
private string EncryptToBytes(string plaintext, string publicKey)
{
if (String.IsNullOrEmpty(publicKey)) throw new ArgumentNullException("publicKey");
byte[] plaintext_Bytes = Encoding.Unicode.GetBytes(plaintext);
_rsa.FromXmlString(publicKey);
byte[] ciphertext = _rsa.Encrypt(plaintext_Bytes, false);
return Convert.ToBase64String(ciphertext);
}
}
And you really should use SecureString
for your plaintext. 而且,您确实应该将SecureString
用于纯文本。
class RsaLibrary2
{
//initializing the RSA object taking the option of a 1024 key size
readonly RSACryptoServiceProvider _rsa = new RSACryptoServiceProvider(1024);
readonly string _privateKey;
readonly string _publicKey;
public RsaLibrary2()
{
_privateKey = _rsa.ToXmlString(true);
_publicKey = _rsa.ToXmlString(false);
}
public SecureString Decrypt(string ciphertext, string privateKey_ = null)
{
if (ciphertext.Length <= 0) throw new ArgumentNullException("ciphertext");
string key = String.IsNullOrEmpty(privateKey_) ? _privateKey : privateKey_;
return DecryptToBytes(ciphertext, key);
}
private SecureString DecryptToBytes(string ciphertext, string privateKey)
{
if (String.IsNullOrEmpty(privateKey)) throw new ArgumentNullException("privateKey");
byte[] ciphertext_Bytes = Convert.FromBase64String(ciphertext);
_rsa.FromXmlString(privateKey);
byte[] plainbytes = _rsa.Decrypt(ciphertext_Bytes, false);
char[] plain = Encoding.Unicode.GetChars(plainbytes);
var retval = new SecureString();
FromArray(retval, ref plain);
return retval;
}
public string Encrypt(SecureString plaintext, string publicKey_ = null)
{
if (plaintext == null) throw new ArgumentNullException("plaintext");
if (plaintext.Length <= 0) throw new ArgumentOutOfRangeException("plaintext");
string key = String.IsNullOrEmpty(publicKey_) ? _publicKey : publicKey_;
return EncryptToBytes(plaintext, key);
}
private string EncryptToBytes(SecureString plaintext, string publicKey)
{
if (String.IsNullOrEmpty(publicKey)) throw new ArgumentNullException("publicKey");
byte[] plaintext_Bytes = SecureStringToByteArray(plaintext);
_rsa.FromXmlString(publicKey);
byte[] ciphertext = _rsa.Encrypt(plaintext_Bytes, false);
return Convert.ToBase64String(ciphertext);
}
// YIKES! Copies the SecureString to a byte[] array; use with caution!
static byte[] SecureStringToByteArray(SecureString secureString)
{
if (secureString == null) throw new ArgumentNullException(/*MSG0*/"secureString");
// copy plaintext from unmanaged memory into managed byte[]s
int stringSize = secureString.Length * sizeof(char); // http://blogs.msdn.com/shawnfa/archive/2005/02/25/380592.aspx
byte[] bytes = new byte[stringSize];
IntPtr pString = Marshal.SecureStringToGlobalAllocUnicode(secureString); // do this last to minimize the availability of "pString"
try // free "pString" even if Copy() throws
{
Marshal.Copy(pString, bytes, 0, stringSize);
}
finally
{
Marshal.ZeroFreeGlobalAllocUnicode(pString); // clear plaintext from unmanaged memory ASAP
}
return bytes;
}
static void ArrayZero<T>(ref T[] array)
{
Array.Clear(array, 0, array.Length); // clear from managed memory
Array.Resize(ref array, 0); // set Length=0 ASAP; even the length can be valuable
array = null; // just to "help" callers know there's nothing in the array anymore
}
static void FromArray(SecureString secureString, ref char[] array)
{
try // clear "array" even if AppendChar() throws
{
for (int i = 0; i < array.Length; i++)
{
secureString.AppendChar(array[i]);
array[i] = default(char); // clear plaintext ASAP
}
}
finally
{
ArrayZero(ref array); // clear plaintext from managed memory
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.