Error with RSA Encrypting Xml file converted into byte[] - c#

This is a follow-on to this SO post in which I learned to generate the RSA key pair and store the Public key in the Settings. I generated my key by:
CspParameters cspParams = new CspParameters();
cspParams.KeyContainerName = "XML_ENC_RSA_KEY";
RSACryptoServiceProvider rsaKey = new RSACryptoServiceProvider(cspParams);
string keyXml = rsaKey.ToXmlString(true);
I copied the public key part of that string into my program settings and it looks like:
"<RSAKeyValue><Modulus>mfXS3Na0XfkjhpjS3sL5XcC9o+j6KXi1LB9yBc4SsTMo1Yk/pFsXr74gNj4aRxKB45+hZH/lSo933NCDEh25du1iMsaH4TGQNkCqi+HDLQjOrdXMMNmaQrLXGlY7UCCfFUnkEUxX51AlyVLzqLycaAt6zm5ljnDXojMC7JoCrTM=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
Does that look valid?
Then I am taking my XML document and trying to convert it to a byte[] for the Encrypt function:
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
XDocument doc = new XDocument();
XElement xml = new XElement("Info",
new XElement("DatabaseServerName", txtServerName.Text),
new XElement("DatabaseUserName", txtDatabaseUserName.Text),
new XElement("DatabasePassword", txtDatabasePassword.Text),
new XElement("ServiceAccount", txtAccount.Text),
new XElement("ServicePassword", txtServicePassword.Text),
new XElement("RegistrationCode", txtRegistrationCode.Text));
doc.Add(xml);
doc.Save(fileName);
// Convert XML doc to byte stream
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fileName);
byte[] fileBytes = Encoding.Default.GetBytes(xmlDoc.OuterXml);
Encrypt(fileBytes);
I am getting a "Syntax Error line1" from the Encrypt function which is:
private static byte[] Encrypt(byte[] bytes)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(Properties.Settings.Default.PublicKeyXml);
return rsa.Encrypt(bytes, true);
}
}
Any ideas? EDIT: The actual error is:
rsa.FromXmlString(Properties.Settings.Default.PublicKeyXml);

I was just looking at your post here looking for information on the RSACryptoServiceProvider. I tried your code and it worked for me, Well, sort of, I never got the error you did until I started reading your message again.
Remove the quotes from your public key in the Properties.Settings. When I saw what you had posted for your public key I went in and added the quotes to my string and I get the exact same error you did.
Where I did get an error but different from yours was getting a bad length error on the encrypt. However, I figured out that if I change the line for converting the XmL to a byte to .ToString() and not .OuterXML it works.
private void button4_Click(object sender, EventArgs e)
{
string fileName = System.IO.Path.Combine(Application.StartupPath, "alphaService.xml");
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fileName);
byte[] fileBytes = Encoding.ASCII.GetBytes(xmlDoc.ToString());
byte[] EncryptedBytes = Encrypt(fileBytes);
string EncryptedString = Encoding.ASCII.GetString(EncryptedBytes);
}
private static byte[] Encrypt(byte[] bytes)
{
using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(Properties.Settings.Default.PublicKeyXml);
return rsa.Encrypt(bytes, false);
}
}
I changed and encoding to ASCII so I could convert the byte array to a string and it's better to do that if you convert to the byte array using the same method.

Related

Encrypt the plain text using public key in client App (html & js) and decrypt the encrypted data using private key in ASP.NET Web API

I have a requirement like
Generate public/private keys in API and store in Data base
Send the public key to client. Here client is plain html with jquery
Client will encrypt the plain text using public key and send to api for further action
API will decrypt the encrypted data using private key which is present in database
Here I am able to generate keys and able to encrypt data in client. But Unable to decrypt the encrypted data in API.
Code to generate Keys
var csp = new RSACryptoServiceProvider(2048);
csp.PersistKeyInCsp = true;
//Private key
var privKey = csp.ExportParameters(true);
//Public key
var pubKey = csp.ExportParameters(false);
string privKeyString = string.Empty;
var sw = new System.IO.StringWriter();
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
xs.Serialize(sw, privKey);
privKeyString = sw.ToString();
//Will be saved in sesssion for later use during decryption
string privateKeyBase64 = Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(privKeyString));
//string privateKeyBase64 = ConvertPrivateKeytoString(privKey);
//This will give public key in the following format which is required by the JS library
//-----BEGIN PUBLIC KEY-----
//XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//-----END PUBLIC KEY-----
publicKey = ConvertPublicKeyForJS(pubKey);
Code in JS
var keySize = parseInt(2048);
var encrypt = new JSEncrypt({ default_key_size: keySize });
encrypt.setPublicKey(pkey);
var encryptedJson = encrypt.encrypt(emailParams);
var emailParamsEncrypted = new Object();
emailParamsEncrypted.PId = pId;
emailParamsEncrypted.EncryptedData = encryptedJson;
Code for Decryption in API (C#)
string plainTextData = string.Empty;
//read the private key from DB
string privKeyString = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(emailKeys.PrivateKey));
var sr = new System.IO.StringReader(privKeyString);
var xs = new System.Xml.Serialization.XmlSerializer(typeof(RSAParameters));
var privKey = (RSAParameters)xs.Deserialize(sr);
var csp = new RSACryptoServiceProvider(2048);
csp.PersistKeyInCsp = true;
csp.FromXmlString(privKeyString);
csp.ImportParameters(csp.ExportParameters(true));
var bytesCypherText = Convert.FromBase64String(cypherText);
//Array.Reverse(bytesCypherText);
//var bytesCypherText1 = System.Text.Encoding.Unicode.GetBytes(cypherText);
//Problematic line
var bytesPlainTextData = csp.Decrypt(bytesCypherText, RSAEncryptionPadding.Pkcs1);
plainTextData = System.Text.Encoding.Unicode.GetString(bytesPlainTextData);
Keys
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAztHqr8CkaC+XvlO/E0I4Zur/eYyJ8WyGZhgzVaZfo2STbf98IP6eQ+jiqIgGywk+EolTf6BubrCI+Hb/I1YSdEd0eI3VMgEpLWATdqvyFIOqdyf3G/ZOPpWvKrM5xMTb62zpzYMdcpizYPJaKn3v3nmt4lMiKM2fV8Yhym90qkvqckEtyiP3Z9xuusiXhbdBgFSXZI4wiV22pZvIoNcqV4xsCLvabnfP0ZZD/4e8CHeBfAzWFoiw3ZgrdgIHvoGFfsR/dI3pDN8kzExeXj3TLE7yHElykB6ROicHlCNsR3G5k2605W/YTbPs6MRRhbz2PdshyR82ewC7dhZu5+6kxQIDAQAB -----END PUBLIC KEY-----
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTE2Ij8+DQo8UlNBUGFyYW1ldGVycyB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4bWxuczp4c2Q9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIj4NCiAgPEV4cG9uZW50PkFRQUI8L0V4cG9uZW50Pg0KICA8TW9kdWx1cz56dEhxcjhDa2FDK1h2bE8vRTBJNFp1ci9lWXlKOFd5R1poZ3pWYVpmbzJTVGJmOThJUDZlUStqaXFJZ0d5d2srRW9sVGY2QnVickNJK0hiL0kxWVNkRWQwZUkzVk1nRXBMV0FUZHF2eUZJT3FkeWYzRy9aT1BwV3ZLck01eE1UYjYyenB6WU1kY3BpellQSmFLbjN2M25tdDRsTWlLTTJmVjhZaHltOTBxa3ZxY2tFdHlpUDNaOXh1dXNpWGhiZEJnRlNYWkk0d2lWMjJwWnZJb05jcVY0eHNDTHZhYm5mUDBaWkQvNGU4Q0hlQmZBeldGb2l3M1pncmRnSUh2b0dGZnNSL2RJM3BETjhrekV4ZVhqM1RMRTd5SEVseWtCNlJPaWNIbENOc1IzRzVrMjYwNVcvWVRiUHM2TVJSaGJ6MlBkc2h5UjgyZXdDN2RoWnU1KzZreFE9PTwvTW9kdWx1cz4NCiAgPFA+MDd0Vzl0T2x2cUNCMU5FUEVLS2tZNGVsNkc0NHV1RHYzNnYrQ1BjbGVMdThuNjAzY0hUWi84Q20rOFBYTklQVDhrcGdhb0trcDFRWjk2QUFqN2Z1ME5BSkovQUpid01xSkFyREZ4VElQeVplQjFVMjNzMDlNem1oVU1CSldlVk54dHFuTjdJYU9BY1JPY0JDa2grc2JKbkdFL1d2cTYySVgwR3g4WUxtQnZjPTwvUD4NCiAgPFE+K2crdDJIRTh5WmZ4bXpLbzFtQ3A2eEJrUFdvclptT1RGY1BocEk5dFEyaUIvZDdaV09yNklpbDJjc1NaZ1FEOEZ4OFdBdlppVU11VGlheG85bS9hN1oreG9ubE1NaFFnWmlhVlFoOVBrN3NtMlBrZlVnWUZKOWFOK01PUW8yMkJLSUZNWThEd1RKMDdBTDh6QVNqTGZKWDJNWmNYd3RZWk1xQ2xiMWFnbHlNPTwvUT4NCiAgPERQPmt6WUh5dWx3cmM5dk5ZWjlVUFdrRWtkNEJOak52TEUwVm5HQTJMN3RZTG8yOVZZNzI0YURJNXpRL084M0s1NFV1THNadWpSSFFzZm9uaEN6RXpteFk2R2hIQkY2bmFLM3BBT1BqUGE0RzZBVGRFbTlNci9FTTE5NFYycTZGVFNuRlFGbGpnWFkwT2VwQkZ3MmJONTB4YlZNMFFmYk1pUWZVd3VjS3V6MS9oVT08L0RQPg0KICA8RFE+WDE3SmUrbzhOOXEyYisyVFRTZlN4bThhKy8xWkRoVGVEUWdITC83dnVpektueXQyRTU2U3hhS3dwVGJzSUxKaWN1TU5QeFgvQ3plSlRwR3Qrb2RRcFI0cDNvQ0ttZkxwSkd5RXNwSkVoR0IxZ1gwSi8vdUJ6ZDdiaU12MWh3OEZtcEF0dFVIcHBCNjNXU0tTN2xkRHZJRnBReUtRRW1RYmVoNmcyZVRkSEtjPTwvRFE+DQogIDxJbnZlcnNlUT55YjNmOXdhMk0zNW1zLzFqNGY1Yk1PLy96SUJJVmF5QWtKL053WDdMcGZGNEFPeDM5azg5TEk3UE9RRDBTb2cwVVl6YXkyTDVXMGhLaDBBdEJXaVczaG9iMDZjZVhrSG9zbWc5cGRWUEtWZy9lRHNrY0Q5V3A2bXZ3amhPSXR4SVdzY0VaQzlNT3NFenZiaEtUQUcxRnE4VGVFcUMxYWlRYlZGQzFlUFY4YXM9PC9JbnZlcnNlUT4NCiAgPEQ+angrendtYVZIOGgzd1cyaEdFbkdVR3FsMjA3SGt6d2dFZjBEWVcxZVYrdGRIMDBqY0kzanBtayttWlJ3NXdjQlhzQ0wrUkZqK3RQT0pldnJpbCtoSzdqYlFDWWUrSmpYRHlDaXQ0Z3NZY2Z3S3IrTWdWeEZMNGhValQ4MFpoZzVmTVdGVXdRK1Y3U1d4aXRRL0lEa2cxZy9YaFZiMlZMYXgxcEV2aHU5WjY4Yi94dUc2YjZybStxVUFzblk3SmFHS3Z5QmNaY1ZzL2VTcDRZQ1YzNHRxUEZhU09uMVJ1VThqcWdQU1hlMHVWMG1lZTUrZlNsdFdIaFJ3N0ZYVko3ZmNXZXRVeE5pc085aXdvTEdKREhpRjkrWXpLWmZ3cnU5Ky9NSEk2dzl6YXZ1TnRESWZtTGlyNlFrVWozODV0ZW5Qak5iQTZOWHJiZThSUk45UGJqOWpRPT08L0Q+DQo8L1JTQVBhcmFtZXRlcnM+
Here, after decrypting I am getting empty byte[0]
why it is returning byte[0] ? What is the root cause for this prolem?
Can you please help me to get it solved

Unable to use existing keys in RSA Cryptoservice provider class

I need to use RSA encryption in my wp8 app and send it to the server. But the trouble I am facing is that I know the public key of the server and I need to encrypt the data in app side using the key. But as far I infer from all the posting here, RSACryptoservice provider class doesn't support a key from another source(Am I wrong?). Is there any way to use the class in such a scenario? Or can this be done by using third party library only?
I tried the following function but still no use. What am I doing wrong here?
public static string RSAEncrypt(string data)
{
try
{
//initialze the byte arrays to the public key information.
string pk = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0cNKUgLdLMpW5BWB+PAlIIIiqhSXk66PQVemUnRs3nowRcBETfUkMIfDcPDM1FXhh+/2FqsnFLveCYl980bylZlBghkjUleknV4dGLfQPuLE7oxk4tbQF6Zk9Fmc9ynxvZ7XDuLmdn/4mdxW7BmcSomLIxkkGHynKkkXk5QcKQIDAQAB";
byte[] PublicKey = Convert.FromBase64String(pk);
//byte[] Exponent = { 1, 0, 1 };
UnicodeEncoding pi = new UnicodeEncoding();
//Values to store encrypted symmetric keys.
byte[] dataBytes = pi.GetBytes(data);
//Create a new instance of RSACryptoServiceProvider.
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
//Create a new instance of RSAParameters.
RSAParameters RSAKeyInfow = new RSAParameters();
//Set RSAKeyInfo to the public key values.
RSAKeyInfow.Modulus = PublicKey;
// RSAKeyInfow.Exponent = Exponent;
//Import key parameters into RSA.
RSA.ImportParameters(RSAKeyInfow);
var rslt = RSA.Encrypt(dataBytes, false);
System.Diagnostics.Debug.WriteLine(rslt);
return Convert.ToBase64String(rslt);
}
catch
{
return null;
}
}
Am calling this function in another page as:
private void Button_Click(object sender, RoutedEventArgs e)
{
var myString = "this is my string data";
var x = Class1.RSAEncrypt(myString);
MessageBox.Show(x);
}
The error I get is "Value cannot be null.
Parameter name: messageBoxText"
I think the problem here is not passing the exponent, but I don't know how.

phpseclib sign and verify in C#

I need to sign the string with private Key using RSA phpseclib and then verify it in C# . I have seen many examples of how to encrypt in C# and decrypt in php, but none of how to sign string in php and verify in .NET.
here is php code:
include('Crypt/RSA.php');
$info = "Something";
$PrivateKey= "<RSAKeyValue><Modulus>3C5QWo4H+............"; //long string
$unsignedString = base64_encode($info);
$signedString = HashAndSignBytes($info, $PrivateKey);
file_put_contents('file.txt', $unsignedString."\n".$signedString);
function HashAndSignBytes($stringToSign, $Key) {
$rsa = new Crypt_RSA();
$rsa->loadKey($Key); // private key
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$signature = $rsa->sign($stringToSign);
return base64_encode($signature);
}
and here is my attempt to read the file and verify it in C#:
const string publicKey = #"<RSAKeyValue><Modulus>3C5QWo4H.....";
TextReader reader = new StreamReader(path, Encoding.ASCII);
var unsignedString = reader.ReadLine();
var signedString = reader.ReadLine();
reader.Close();
if (VerifySignedHash(unsignedString,signedString, publicKey)) {
//some code
}
private bool VerifySignedHash(string stringToVerify, string signedString, string publicKey)
{
var byteConverter = new ASCIIEncoding();
var dataToVerify = Convert.FromBase64String(stringToVerify);
var signedData = Convert.FromBase64String(signedString);
try
{
// Create a new instance of RSACryptoServiceProvider using the
// key from RSAParameters.
var rsaAlg = new RSACryptoServiceProvider();
rsaAlg.FromXmlString(publicKey);
// 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;
}
}
verfication fails...
In your "signing" code, you base64encode the original string, then write that string to the output file. However, on the C# side, you read that value into unsignedString, but never reverse the base64 encoding.
The end result is that you're trying to verify the bytes of the base64Encoded string, not the data itself, so the VerifyData step fails.
Think that's your problem.
Modifying the following line might solve the problem:
var dataToVerify = Convert.FromBase64String(stringToVerify);

C# RSA Decrypt Using Private Key

I've been searching but I can't seem to find a simple way of decrypting using RSA.
I have generated a public and private key, they are stored in two separate files and are in the XML format. I have no problem associating the public key to the RSACryptoServiceProvider object using FromXmlString, and then encrypting a string. My confusion comes when trying to decrypt an encrypted string. I'm not sure how I associate the private key data with the RSACryptoServiceProvider so that I can use the Decrypt function.
Any help would be appreciated.
EDIT:
The format of the public and private key is XML generated by the RSACryptoServiceProvider object, which I just put into a file:
<RSAKeyValue><Modulus>vS7Y5up+6kHMx7hQjKA6sKlIVASaw ... etc ...
I load the public key using this code:
StreamReader sr = new StreamReader(HttpContext.Current.Server.MapPath("public.key"));
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(sr.ReadToEnd().ToString());
I currently haven't tried anything with the private key yet, since I'm not sure where to start.
I don't know your situation but I would suggest that you store you key information in a KeyContainer. If you do this you can access the keyContainer by name and can do something like this.
// retrieves the maximum number of characters that can be decrypted at once
private int getMaxBlockSize(int keySize){
int max = ((int)(keysize/8/3) )* 4
if (keySize / 8 mod 3 != 0){
max += 4
}
return max;
}
public string decrypt(string msg, string containerName){
CspParameters params = new CspParameters();
params.KeyContainerName = containerName;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(params);
StringBuilder decryptedMsg = new StringBuilder();
int maxDecryptSize = getMaxBlockSize(rsa.KeySize);
int iterationCount = Math.Floor(msg.length / maxDecryptSize)
for(int i=0; i<iterationCount; i++){
int start = i * maxDecryptSize;
int blkSize = Math.min(start + maxDecryptSize, msg.Length);
Byte[] msgBytes = System.Convert.FromBase64String(msg.Substring(start, blkSize));
decryptedMsg.Append(System.Text.Encoding.Unicode.GetString(RSAProvider.Decrypt(msgBytes, false));
}
return decryptedMsg.ToString();
}
I haven't tested this out so there might be a bug in here but the you get the idea.
if you have private key in text format
like given below
-----BEGIN RSA PRIVATE KEY-----
text....
-----END RSA PRIVATE KEY-----
public string RsaDecryptWithPrivate(string base64Input, string privateKey)
{
var bytesToDecrypt = Convert.FromBase64String(base64Input);
AsymmetricCipherKeyPair keyPair;
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(privateKey))
{
keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject();//fetch key pair from text file
decryptEngine.Init(false, keyPair.Private);
}
var decrypted = Encoding.UTF8.GetString(decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length));
return decrypted;
}

How to verify a signature with a public key provided in .pem File?

How can I verify a signature with a public key provided in .pem File?
I use the flowing code:
RSACryptoServiceProvider CrRsa;
var reader21 = File.OpenText(#"C:GTLpublicKey.pem");
var x = new PemReader(reader21);
var y = (RsaKeyParameters)x.ReadObject();
CrRsa = (RSACryptoServiceProvider)RSACryptoServiceProvider.Create();
RSAParameters pa = new RSAParameters();
pa.Modulus = y.Modulus.ToByteArray();
pa.Exponent = y.Exponent.ToByteArray();
CrRsa.ImportParameters(pa);
y returns null, results in an Error at pa.Modulus = y.Modulus.ToByteArray();
RSACryptoServiceProvider RSAVerifier = new RSACryptoServiceProvider();
//Read public Key From Text File.
StreamReader PubKeyReader = File.OpenText(txtPublicKeyFile.Text);
string publicKey = PubKeyReader.ReadToEnd();
//Adding public key to RSACryptoServiceProvider object.
RSAVerifier.FromXmlString(publicKey);
//Reading the Signature to verify.
FileStream Signature = new FileStream(txtVerifySign.Text, FileMode.Open, FileAccess.Read);
BinaryReader SignatureReader = new BinaryReader(Signature);
byte[] SignatureData = SignatureReader.ReadBytes((int)Signature.Length);
//Reading the Signed File for Verification.
FileStream Verifyfile = new FileStream(txtVerifyFile.Text, FileMode.Open, FileAccess.Read);
BinaryReader VerifyFileReader = new BinaryReader(Verifyfile);
byte[] VerifyFileData = VerifyFileReader.ReadBytes((int)Verifyfile.Length);
//Comparing.
bool isValidsignature = RSAVerifier.VerifyData(VerifyFileData, "SHA1", SignatureData);
if (isValidsignature)
{
Signature.Close();
Verifyfile.Close();
}
else
{
Signature.Close();
Verifyfile.Close();
}
I disagree with the proposed answer.
RSACryptoServiceProvider can't read a PEM file through "FromXMLString".
However, it gave me the idea to export the PEM file to XML.
I found this site that makes the online conversion
Then it worked perfectly!
Not sure but probably is the problem that you forgot a backsslash:
var reader21 = File.OpenText(#"C:\GTLpublicKey.pem");
// ^

Categories

Resources