Decrypt a byte[] signed with a private key - c#

I have two XML files with private and public keys generated by the RSACryptoServiceProvider class. I have turned a random string into a byte array, and using the private key, I have encrypted it. But how do I use the public key to decrypt the byte[] again? Here's what I have so far:
class Program
{
static void Main(string[] args)
{
RSACryptoServiceProvider encryptor = new RSACryptoServiceProvider();
encryptor.FromXmlString(GetPrivateKey());
string unencryptedString = "This string could only have been send by me.";
byte[] unencryptedByteArray = Encoding.Unicode.GetBytes(unencryptedString);
byte[] encryptedByteArray = encryptor.SignData(unencryptedByteArray, new SHA1CryptoServiceProvider());
byte[] decryptedByteArray; //how do I decrypt the array again?
string decryptedString = System.Text.Encoding.Unicode.GetString(decryptedByteArray);
Console.WriteLine(decryptedString);
Console.ReadKey();
}
private static string GetPrivateKey()
{
using (TextReader reader = new StreamReader(#"path to private key file generated by the ToXmlString method"))
{
string privateKey = reader.ReadToEnd();
reader.Close();
return privateKey;
}
}
private static string GetPublicKey()
{
using (TextReader reader = new StreamReader(#"path to public key file generated by the ToXmlString method"))
{
string privateKey = reader.ReadToEnd();
reader.Close();
return privateKey;
}
}
}

You can't decrypt back to the value of unencryptedString. According to the documentation, the method RSACryptoServiceProvider.SignData computes the hash value of the specified data and signs it. As hashes are non-reversible by design, you can't decrypt back to the original value.
However, you can use RSACryptoServiceProvider to encrypt and decrypt data. Below I have included an example application from the documentation on MSDN
using System;
using System.Security.Cryptography;
using System.Text;
class RSACSPSample
{
static void Main()
{
try
{
//Create a UnicodeEncoder to convert between byte array and string.
UnicodeEncoding ByteConverter = new UnicodeEncoding();
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = ByteConverter.GetBytes("Data to Encrypt");
byte[] encryptedData;
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
//Pass the data to DECRYPT, the private key information
//(using RSACryptoServiceProvider.ExportParameters(true),
//and a boolean flag specifying no OAEP padding.
decryptedData = RSADecrypt(encryptedData, RSA.ExportParameters(true), false);
//Display the decrypted plaintext to the console.
Console.WriteLine("Decrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
}
}
catch (ArgumentNullException)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine("Encryption failed.");
}
}
static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.ToString());
return null;
}
}
}

Related

Can't get C# RSA Decryption answer

I am trying to encrypt and decrypt a string "Dilan" using C# RSA Encryption method. Although at the decrypting part I cannot get an answer. Then I use my keys in this page https://8gwifi.org/RSAFunctionality?keysize=2048 and try to get an answer.
From the encryption part,
Answer:
Decrypted plaintext: Dilan
Encripted plaintext: ODPcL+q4UaDlSo3CGBVww0DHnjv2AgBrr8gZD6HozQnyVoO03G01m9H/FAxQfiK9tFMRmxiMBMLnMMs53UxcSAa4XwCmOoxbOT6GeU+NUAIc1FtwckSQW+O/fB8Xg5OC2K7kaqX52Aa4xGN/I0yIXhJH7rrPHjUejbRnNeXOW1E=
For the https://8gwifi.org/RSAFunctionality?keysize=2048 page, I'm using
Public Key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjARAj29gfyS6C7sQSjsJ
ulPGa9RMSntxJHvJRZG3KSo5lLKVLzFnIv0h6AMUOMQ/e0aic3LOd742ebKrxQdD
RA/as/zEqPOTh7t6ahQok33gjcn6+DP95RMfj85n0Cdm1GV0AjFdBhkYf189u1De
w6sSwUF2PhEky3wki7jR1UKWl7y7h0HEmsYhaDATBJYSz+3u1N5aN0X5gysv5KoP
QJ7D8Y8qNwFZFM39TUgeB4ZFT/QR853adNLinZ8/6rnkFZQO1BSChFXC0+2hB7/Z
4h9RAziLPXenmATvk8vxXXothRcKrP2n/mY8YrBfiGM8rvENdo/xqW0WEsFvZEbI
ywIDAQAB
-----END PUBLIC KEY-----
Private Key:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAjARAj29gfyS6C7sQSjsJulPGa9RMSntxJHvJRZG3KSo5lLKV
LzFnIv0h6AMUOMQ/e0aic3LOd742ebKrxQdDRA/as/zEqPOTh7t6ahQok33gjcn6
+DP95RMfj85n0Cdm1GV0AjFdBhkYf189u1Dew6sSwUF2PhEky3wki7jR1UKWl7y7
h0HEmsYhaDATBJYSz+3u1N5aN0X5gysv5KoPQJ7D8Y8qNwFZFM39TUgeB4ZFT/QR
853adNLinZ8/6rnkFZQO1BSChFXC0+2hB7/Z4h9RAziLPXenmATvk8vxXXothRcK
rP2n/mY8YrBfiGM8rvENdo/xqW0WEsFvZEbIywIDAQABAoIBAHCB9jKLZ3mi1FAa
xzMuj1mGeZkppQfwevC6+vcI6KmOQWiHuzKJuvs1depNlxEqOGxhTKYB6X/0eyd8
92NBu75UEwOvp4Ku/qwBbJMSkaw6aJbmZuDMPka1ABZ435g2IP2oa/hbHAmLXtDy
gdMjX2zQ6Sga5t1mvy83GNKg9xMp1z1UG3ryQGjcZWTOdCFNakS+Tr6X4SlXSfUS
FFi9aup1u9RJQTh2I5xoXf2GuDyad40GUGz/shC0Gwvd6DBsLdUutuipuuEuaHMx
Hoc+RdnjkXPF4lIP8lJ0Q4+HTGisGFaeZhiDRenuAxY8pUtLA/uVy8IUE8pNje0m
iOWr6hkCgYEAvoN0hopinQ9nZv7TnTuqZJrdPrSzoBvZyhToV5bNUqF0w5S7cIZG
JepyoXDf/VPwkO7uLr+HciT5p3nxMjzLr+OSmZXw+pKGYIVsbOl6EvSc1yl2itvs
H8osH1rTRi5MekjYPW6G+m8XQlF+kQnvctQop9pjiunJY3ynUCuB80UCgYEAvCU9
y4genKb0MmCXl9HjFT3MUQjaoPpjU5oNJmlH8cBUVkBsE1L10R2XXBXJLzS8ZRHU
GJfp0wearV/yCIjaCH7ZpgOe1Hin40xBiqW2tsNidnhp8tj0zzWjJ4q6phSAkMUt
4Ep6mBYmr7orTzJbbWFg0h1PMbcLA2lVDhguBM8CgYABP0ELBGri1k/5958Q/2v9
HppmJ66pVKVXUk23DRCpAs+N3DJh6S8aXm+DqQZ+VQdVG4tJmQ1c7OsJcp3mk0lO
DHJQORALw9vHU/hCukCHUTyZl/bjr87a4mrphaGuau0rO8DWnhuaFhIT6A6pCmSb
3tGpT5+pMCCWWyGJP8+o9QKBgQCh6ub4j2fQ5znHVSuBQ+dLM4jvwE/vNC1hGHXy
ta5t1lh+dijMpJva4L2PSUx/7MGptaMzmyFnNOcgCC9SuvvxTcHfxsPdFQ1fZxQM
zzqkpRfK3yxHDAH7hayo7hJdtc1DSf6GRXKmCoI2v2BgYvUd+C0MBp9OKLo4sGC7
pYGNLwKBgQCFNf6D3WCTNSI51V5PXST6Ygzwp7rgL29jh7Icqd9X6zQKLtedY6lf
jqoLwo9/DlVImm6SXmnN1sAg2IBFQXTA8yof/TWhg841UFobxGN0plfWrwFW4ifl
AHnmBg32HZ2CxlQLDUKBdWWLSIHfL/RgHM4swxaueBxNbHRVKhWyCg==
-----END RSA PRIVATE KEY-----
String:
Dilan
C# Code:
using System;
using System.Security.Cryptography;
using System.Text;
namespace RSACSPSample
{
class RSACSPSample
{
static void Main()
{
string publicKey = "<RSAKeyValue><Modulus>b1kOI/0aD04EL6brX81csy3xaSAKOezF1n/g+mbyTR4rYQMWl4QMiG8XHx8E1KgERNjenbwePO0YcqH0FJP01sDPfiqleLK7FcoXJ00K9COcBCOzBf3OlSmpGYaPQ00O9pMGxXjyOc8a/wef//dPXIeXBeTxMrkR99vScWyck5E=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
string privateKey = "<RSAKeyValue><Modulus>b1kOI/0aD04EL6brX81csy3xaSAKOezF1n/g+mbyTR4rYQMWl4QMiG8XHx8E1KgERNjenbwePO0YcqH0FJP01sDPfiqleLK7FcoXJ00K9COcBCOzBf3OlSmpGYaPQ00O9pMGxXjyOc8a/wef//dPXIeXBeTxMrkR99vScWyck5E=</Modulus><Exponent>AQAB</Exponent><P>zSih4lMrHGBRq6PJPvYGevP8WbKAnQwERYi25K2zAIUrUdSWVVOQ7UjuVC1Tfw1Hg57Wal+/jTXjUcmRPgJr0Q==</P><Q>ivEEhXTAwQ2ZnSoEpiSlMW8Q/s6SB4agafZPpKajiOjqWv9y4E0OV1ZFe0GcbQlGgLAmfyWr5TgBYtr+ZJZbwQ==</Q><DP>izD2JEepCCeRQZJuB3mEDAddPr4M5IAypbqL27q9p6yyJ2LEXD/GJDdG+3WFIL4xtusdLi6oF3ZoNCU9lYSvAQ==</DP><DQ>D/Jt1Gt8HCxVb0Z9VhxqoWvgBX7sH9UB4GeW6Iz/xB0HmP4szzXI6ZlLTERRkeo4n1iYcot+WUa+UfxUqnLfgQ==</DQ><InverseQ>keZ+2rPqijIf0uW7MK7v9OHw7+eecPxXbbZAlDNxIUZeMdPuAR/JBUPPS2rqvIb0BJG28dwyaSAIaSfxqJoH4g==</InverseQ><D>SHIY0TGMEwkfkCF6Ywqqlan+t/cwsB9tWPI63rC8VZCbiLMJr+sqfFpLIOR9sB7hKCoyLU6IHfvlPDBDLmBVm8RVC9ytaUQewNj9cD5AB+YKGgh6p2oXpY7WcSRxgjqGIc2klPj3zyTrBn247kde3n5sD+wFY9KCTjPfllhpwAE=</D></RSAKeyValue>";
try
{
//Create a UnicodeEncoder to convert between byte array and string.
UnicodeEncoding ByteConverter = new UnicodeEncoding();
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = ByteConverter.GetBytes("Dilan");
byte[] encryptedData;
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider to generate
//public and private key data.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
encryptedData = RSAEncrypt(dataToEncrypt, publicKey, false);
var base64 = Convert.ToBase64String(encryptedData);
//Pass the data to DECRYPT, the private key information
//(using RSACryptoServiceProvider.ExportParameters(true),
//and a boolean flag specifying no OAEP padding.
decryptedData = RSADecrypt(encryptedData, privateKey, false);
//Display the decrypted plaintext to the console.
Console.WriteLine("Decrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
Console.WriteLine("Encripted plaintext: {0}", base64);
Console.ReadKey();
}
}
catch (ArgumentNullException)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine("Encryption failed.");
}
}
public static byte[] RSAEncrypt(byte[] DataToEncrypt, string publicKey, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//to include the public key information.
RSA.FromXmlString(publicKey);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
public static byte[] RSADecrypt(byte[] DataToDecrypt, string privateKey, bool DoOAEPPadding)
{
try
{
byte[] decryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.FromXmlString(privateKey);
//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.ToString());
return null;
}
}
}
}

Encription the data and verifying the signature C#

I want to make 2 applications. The first will crypt the file and sign it. The second will be encrypt and verify the data. I use the following code as example.
using System;
using System.Security.Cryptography;
using System.Text;
class RSACSPSample
{
static void Main()
{
try
{
// Create a UnicodeEncoder to convert between byte array and string.
ASCIIEncoding ByteConverter = new ASCIIEncoding();
string dataString = "Data to Sign";
// Create byte arrays to hold original, encrypted, and decrypted data.
byte[] originalData = ByteConverter.GetBytes(dataString);
byte[] signedData;
// Create a new instance of the RSACryptoServiceProvider class
// and automatically create a new key-pair.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
// Export the key information to an RSAParameters object.
// You must pass true to export the private key for signing.
// However, you do not need to export the private key
// for verification.
RSAParameters Key = RSAalg.ExportParameters(true);
// Hash and sign the data.
signedData = HashAndSignBytes(originalData, Key);
// Verify the data and display the result to the
// console.
if(VerifySignedHash(originalData, signedData, Key))
{
Console.WriteLine("The data was verified.");
}
else
{
Console.WriteLine("The data does not match the signature.");
}
}
catch(ArgumentNullException)
{
Console.WriteLine("The data was not signed or verified");
}
}
public static byte[] HashAndSignBytes(byte[] DataToSign, RSAParameters Key)
{
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
RSAalg.ImportParameters(Key);
// Hash and sign the data. Pass a new instance of SHA1CryptoServiceProvider
// to specify the use of SHA1 for hashing.
return RSAalg.SignData(DataToSign, new SHA1CryptoServiceProvider());
}
catch(CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
public static bool VerifySignedHash(byte[] DataToVerify, byte[] SignedData, RSAParameters Key)
{
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider();
RSAalg.ImportParameters(Key);
// Verify the data using the signature. Pass a new instance of SHA1CryptoServiceProvider
// to specify the use of SHA1 for hashing.
return RSAalg.VerifyData(DataToVerify, new SHA1CryptoServiceProvider(), SignedData);
}
catch(CryptographicException e)
{
Console.WriteLine(e.Message);
return false;
}
}
}
The problem is I can not understand how can I get OriginalData (1-st parameter) for the function VerifySignedHash? I mean the application (signature checker) will read the signed data. How can I convert the signed data to original data for the data verifying?

Encode/Decode in UWP using asymmetric keys

I'm trying to work out a way to encrypt a string using a private key, and decrypt it using a public one. I generated the keys using OpenSSL as described in:
http://www.akadia.com/services/ssh_test_certificate.html
This is what I have currently
public static string Encrypt(string str, string key)
{
try
{
key = key.Replace(Environment.NewLine, "");
IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(key);
AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey publicKey = provider.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
IBuffer dataBuffer = CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(str));
var encryptedData = CryptographicEngine.Encrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
catch (Exception e)
{
throw;
return "Error in Encryption:With RSA ";
}
}
However on the ImportPublicKey method I'm getting an exceptin ASN1 corrupted data
the string key passed to that method has following format:
var privateKey =
#"MIICXwIBAAKBgQDUTqfSknFiQx3aepORHJycWck007cfU4fXluTIyf6U9ipDhyPD
....
yDxwZVmexltyK5Bwc26lmb+5EtTEic+kZToYWcCucF8lsok=";
so the contents of the OpenSSL generated key file without this part:
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
Ok, so my code was pretty wrong, as I wanted to encrypt with the private key, but used the ImportPublicKey function, the correct way should be;
public static string Encrypt(string str, string key)
{
try
{
key = key.Replace(Environment.NewLine, "");
IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(key);
AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
var keyPar = provider.ImportKeyPair(keyBuffer, CryptographicPrivateKeyBlobType.Pkcs1RsaPrivateKey);
//CryptographicKey publicKey = provider.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
IBuffer dataBuffer = CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(str));
var encryptedData = CryptographicEngine.Encrypt(keyPar, dataBuffer, null);
var encryptedStr = CryptographicBuffer.EncodeToBase64String(encryptedData);
var signature = CryptographicEngine.Sign(keyPar, dataBuffer);
var signatureStr = CryptographicBuffer.EncodeToBase64String(signature);
return encryptedStr;
}
catch (Exception e)
{
throw;
return "Error in Encryption:With RSA ";
}
}
and this works to encrypt the string using the RSA private key.
However, when I try to decrypt using the public key, using following similar method;
public static string Decrypt(string str, string key)
{
try
{
key = key.Replace(Environment.NewLine, "");
IBuffer keyBuffer = CryptographicBuffer.DecodeFromBase64String(key);
AsymmetricKeyAlgorithmProvider provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaSignPkcs1Sha256);
CryptographicKey publicKey = provider.ImportPublicKey(keyBuffer, CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
IBuffer dataBuffer = CryptographicBuffer.CreateFromByteArray(Encoding.UTF8.GetBytes(str));
var encryptedData = CryptographicEngine.Decrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
catch (Exception e)
{
throw;
return "Error in Decryption:With RSA ";
}
}
I'm getting an Method or operation not implemented exception, either there is still something wrong, or the private-encrypt/public-decrypt method is not yet there in UWP.
What I ended doing is to get the nuget package Portable.BouncyCastle-Signed and follow the code snippet from this answer:
C# BouncyCastle - RSA Encryption with Public/Private keys
Works like a sharm.

CryptographicException intermittently occurs when encrypting/decrypting with RSA

I'm trying to encrypt and decrypt data using RSA in C#. I have the following MSTest unit test:
const string rawPassword = "mypass";
// Encrypt
string publicKey, privateKey;
string encryptedPassword = RSAUtils.Encrypt(rawPassword, out publicKey, out privateKey);
Assert.AreNotEqual(rawPassword, encryptedPassword,
"Raw password and encrypted password should not be equal");
// Decrypt
string decryptedPassword = RSAUtils.Decrypt(encryptedPassword, privateKey);
Assert.AreEqual(rawPassword, decryptedPassword,
"Did not get expected decrypted password");
It fails during decryption, but only sometimes. It seems like whenever I set breakpoints and step through the test, it passes. This made me think perhaps something wasn't finishing in time for decryption to occur successfully, and me slowing stepping through it while debugging gave it enough time to complete. When it fails, the line it seems to fail at is decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); in the following method:
public static string Decrypt(string textToDecrypt, string privateKeyXml)
{
if (string.IsNullOrEmpty(textToDecrypt))
{
throw new ArgumentException(
"Cannot decrypt null or blank string"
);
}
if (string.IsNullOrEmpty(privateKeyXml))
{
throw new ArgumentException("Invalid private key XML given");
}
byte[] bytesToDecrypt = ByteConverter.GetBytes(textToDecrypt);
byte[] decryptedBytes;
using (var rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(privateKeyXml);
decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); // fail here
}
return ByteConverter.GetString(decryptedBytes);
}
It fails with this exception:
System.Security.Cryptography.CryptographicException: Bad Data
My Encrypt method is as follows:
public static string Encrypt(string textToEncrypt, out string publicKey,
out string privateKey)
{
byte[] bytesToEncrypt = ByteConverter.GetBytes(textToEncrypt);
byte[] encryptedBytes;
using (var rsa = new RSACryptoServiceProvider())
{
encryptedBytes = rsa.Encrypt(bytesToEncrypt, false);
publicKey = rsa.ToXmlString(false);
privateKey = rsa.ToXmlString(true);
}
return ByteConverter.GetString(encryptedBytes);
}
The ByteConverter used throughout is just the following:
public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding();
I've seen a few questions on StackOverflow about RSA encryption and decryption with .NET. This one was due to encrypting with the private key and trying to decrypt with the public key, but I don't think I'm doing that. This question has the same exception as me, but the selected answer was to use OpenSSL.NET, which I would prefer not to do.
What am I doing wrong?
Could you replace ByteConverter.GetBytes with Convert.FromBase64String and replace ByteConverter.GetString with Convert.ToBase64String and see if that helps. Bad Data exception usually means that you have an invalid character in the data or that the length is not the correct length for decrypting. I think using the Convert functions might fix your problems.
public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding();
public static string Encrypt(string textToEncrypt, out string publicKey,
out string privateKey)
{
byte[] bytesToEncrypt = ByteConverter.GetBytes(textToEncrypt);
byte[] encryptedBytes;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
encryptedBytes = rsa.Encrypt(bytesToEncrypt, false);
publicKey = rsa.ToXmlString(false);
privateKey = rsa.ToXmlString(true);
}
return Convert.ToBase64String(encryptedBytes);
}
public static string Decrypt(string textToDecrypt, string privateKeyXml)
{
if (string.IsNullOrEmpty(textToDecrypt))
{
throw new ArgumentException(
"Cannot decrypt null or blank string"
);
}
if (string.IsNullOrEmpty(privateKeyXml))
{
throw new ArgumentException("Invalid private key XML given");
}
byte[] bytesToDecrypt = Convert.FromBase64String(textToDecrypt);
byte[] decryptedBytes;
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(privateKeyXml);
decryptedBytes = rsa.Decrypt(bytesToDecrypt, false); // fail here
}
return ByteConverter.GetString(decryptedBytes);
}
Your problem is with the conversion from bytes to string. Not all sequences of bytes are a valid UTF-16 encoding and you are using a UnicodeEncoding that silently ignores invalid bytes. If you used
public static readonly UnicodeEncoding ByteConverter = new UnicodeEncoding(false, false, true);
instead, your code would have failed when trying to convert the bytes instead of silently replacing the invalid byte-pairs with 0xFFFD.
The fact that the test worked while debugging was a coincidence. You are using a random RSA key-pair, so sometimes you will get a encryption that is a valid UTF-16 encoding.
The fix is, as SwDevMan81 suggests, to use an encoding that can convert all possible byte-arrays. F.x. Base64-encoding.
I would recommend using this class, sadly I don't remember the original author though..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace Encryption
{
class AsymmetricED
{
private static RSAParameters param = new RSAParameters();
/// <summary>
/// Get Parameters
/// </summary>
/// <param name="pp">Export private parameters?</param>
/// <returns></returns>
public static RSAParameters GenerateKeys(bool pp)
{
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
if (param.Equals(new RSAParameters()))
{
param = RSA.ExportParameters(true);
}
RSA.ImportParameters(param);
return RSA.ExportParameters(pp);
}
static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
return RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
return RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
ConsoleColor col = Console.BackgroundColor;
Console.BackgroundColor = ConsoleColor.Red;
Console.WriteLine(e.ToString());
Console.BackgroundColor = col;
return null;
}
}
}
}
Use as:
Encryption.AsymmetricED.RSAEncrypt(Data, GenerateKeys(false), false);
Encryption.AsymmetricED.RSADecrypt(Data, GenerateKeys(true), false);
EDIT:
I also recommend that you don't use this for large data encryption. Usually you would encrypt the actual data with a symmetric algorithm (AES, etc), then encrypt the symmetric key (randomly generated) with the RSA algorithm, then send the rsa encrypted symmetric key, and the symmetric key data..
You should also look at RSA signing, to make sure the data is coming from where it says it is..

C# Problem encrypting using RSA

I am using this function which I pulled off MSDN
static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
try
{
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This only needs
//toinclude the public key information.
RSA.ImportParameters(RSAKeyInfo);
//Encrypt the passed byte array and specify OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
}
return encryptedData;
}
//Catch and display a CryptographicException
//to the console.
catch (CryptographicException e)
{
Console.WriteLine(e.Message);
return null;
}
}
I am calling the method from here:
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Pass the data to ENCRYPT, the public key information
//(using RSACryptoServiceProvider.ExportParameters(false),
//and a boolean flag specifying no OAEP padding.
encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
But I am getting this error message:
Key not valid for use in specified state.
Any ideas what is going wrong?
The code works fine!! I tried it, I think you may have a problem in decryption as you should use the same keys
Unfortunately i have no idea about your Rsa problem but you may want to try this from here , which i use for a long time.
public static string Encrypt(this string stringToEncrypt, string key)
{
if (string.IsNullOrEmpty(stringToEncrypt))
{
throw new ArgumentException("An empty string value cannot be encrypted.");
}
if (string.IsNullOrEmpty(key))
{
throw new ArgumentException("Cannot encrypt using an empty key. Please supply an encryption key.");
}
System.Security.Cryptography.CspParameters cspp = new System.Security.Cryptography.CspParameters();
cspp.KeyContainerName = key;
System.Security.Cryptography.RSACryptoServiceProvider rsa = new System.Security.Cryptography.RSACryptoServiceProvider(cspp);
rsa.PersistKeyInCsp = true;
byte[] bytes = rsa.Encrypt(System.Text.UTF8Encoding.UTF8.GetBytes(stringToEncrypt), true);
return BitConverter.ToString(bytes);
}
You can also find Decrypt Extension there. I hope it'll help.

Categories