I'm told that for asymmetric cryptography you encrypt plaintext with your public key and decrypt it with your private key. So i've tried the following:
static void Main(string[] args)
{
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
string pubkey = rsa.ToXmlString(false);
string prikey = rsa.ToXmlString(true);
byte[] someThing = RSAEncrypt(Encoding.Unicode.GetBytes("Hello World"), pubkey);
byte[] anotherThing = RSADecrypt(someThing, prikey);
Console.WriteLine(Convert.ToBase64String(anotherThing));
}
and the encrypt and decrypt functions
public static byte[] RSAEncrypt(byte[] plaintext, string destKey)
{
byte[] encryptedData;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(destKey);
encryptedData = rsa.Encrypt(plaintext, true);
rsa.Dispose();
return encryptedData;
}
public static byte[] RSADecrypt(byte[] ciphertext, string srcKey)
{
byte[] decryptedData;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(srcKey);
decryptedData = rsa.Decrypt(ciphertext, true);
rsa.Dispose();
return decryptedData;
}
I'm expecting the console to display Hello World, but it displays this SABlAGwAbABvACAAVwBvAHIAbABkAA==. Am i using RSACryptoServiceProvider wrongly?
It is base 64, decode the string and you will get "Hello world".
Your last line should read:
Console.WriteLine(Encoding.Unicode.GetString(anotherThing));
Currently you are converting the decrypted string to Base64 encoding
Related
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;
}
}
}
}
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;
}
}
}
I have the following code in C#:
Main Class
X509Certificate2 cert = new X509Certificate2("C:/test.pfx", "hello", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Encryption enc = new Encryption();
string encrypted = enc.Encrypt("hello there", cert);
string decrypted = enc.Decrypt(encrypted, cert);
Console.WriteLine("Encrypted Text: " + encrypted);
Console.WriteLine("Decrypted Text: " + decrypted);
Encryption Class
public string Encrypt(string plainText, X509Certificate2 cert)
{
RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] encryptedBytes = publicKey.Encrypt(plainBytes, false);
string encryptedText = encryptedBytes.ToString();
return encryptedText;
}
public string Decrypt(string encryptedText, X509Certificate2 cert)
{
RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
byte[] encryptedBytes = Encoding.UTF8.GetBytes(encryptedText);
byte[] decryptedBytes = privateKey.Decrypt(encryptedBytes, false);
string decryptedText = decryptedBytes.ToString();
return decryptedText;
}
As you can see, in the main class I am importing a certificate. Then I am creating an instance of the Encryption class. Then I pass plaintext to the Encrypt method along with the certificate in order to get the encrypted text. Afterwards, I pass the encrypted text to the Decrypt method to get the plaintext back.
My problem is that the result of printing the encrypted text is System.[]Byte (if I comment out the decryption call). If I do not comment out the decryption call, I get a Cryptographic Exception: Bad Data in the decryption method.
I guess that the encryptedBytes array is not being converted correctly to string. Furthermore, I am not sure if I am forming the RSAEncryptionProvider correctly. How can I solve this please?
Update
I solved one issue. When converting from byte array to string, I had to use Encoding.UTF8.GetString(EncryptedBytes). The problem now is that the decrypt method is giving me another cryptographic exception (he data to be decrypted exceeds the maximum for this modulus of 128 bytes).
Does anybody know why this is happening and how to solve it?
you can use base64 Format to convert type of variable (encryptedText) parameter by replace the functions
public string Encrypt(string plainText, X509Certificate2 cert)
{
RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
byte[] encryptedBytes = publicKey.Encrypt(plainBytes, false);
string encryptedText = Convert.ToBase64String(encryptedBytes);
return encryptedText;
}
public string Decrypt(string encryptedText, X509Certificate2 cert)
{
RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PrivateKey;
byte[] encryptedBytes = Convert.FromBase64String(encryptedText);
byte[] decryptedBytes = privateKey.Decrypt(encryptedBytes, false);
string decryptedText = Encoding.UTF8.GetString(decryptedBytes);
return decryptedText;
}
Don't treat encrypted data as a string. Encryption algorithms work on binary data, and produce binary data, which cannot be interpreted as a string. It's naive to think that UTF-8 or any other encoding will be able to interpret any given chunk of binary data as a valid character string.
In your case, if you need to output encrypted data to the console for debugging purposes, go ahead with byte[] and dump it in hexadecimal, like this:
for (int i = 0; i < data.Length; i++)
{
Console.Write(data[i].ToString("X2"));
Console.Write(" ");
if ((i+1) % 16 == 0) Console.WriteLine();
}
I am trying to encrypt strings in .NET by using a RSA algorithm and decrypt the result in Java. At the moment, I have been able to do the opposite (Encrypt in Java, Decrypt in .NET).
Here I have my code that actually works (JAVA encryption):
byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPublicKeySpec rsaPubKey = new RSAPublicKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(rsaPubKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] plainBytes = new String("big kitty dancing").getBytes("UTF-8");
byte[] cipherData = cipher.doFinal( plainBytes );
String encryptedString = Base64.encode(cipherData);
return encryptedString;
And (.NET decryption)
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>+lXMCEwIN/7+eMpBrq87kQppxu3jJBTwztGTfXNaPUTx+A6uqRwug5oHBbSpYXKNDNCBzVm/0VxB3bo4FJx+ZQ==</P><Q>yasOGaJaE9xlF9T2xRuKeG9ZxCiyjhYaYB/mbtL+SIbtkRLi/AxaU4g2Il/UxhxhSXArKxIzV28zktispPJx1Q==</Q><DP>ueRgQIEFUV+fY979a1RgrVHIPpqEI1URhOMH3Q59oiXCcOumM5njyIHmWQxRAzXnG+7xlKXi1PrnRll0L4oOKQ==</DP><DQ>dfEMNgG1HJhwpxdtmqkYuoakwQvsIRzcIAuIAJh1DoWaupWJGk8/JEstHb1d+t7uJrzrAi2KyT/HscH2diE0YQ==</DQ><InverseQ>YoYF9PF6FiC0YngVeaC/eqt/ea8wMYNN3YO1LuzWpcy2exPRj2U0ZbWMvHXMUb4ea2qmhZGx1QlK4ULAuWKpXQ==</InverseQ><D>g1WAWI4pEK9TA7CA2Yyy/2FzzNiu0uQCuE2TZYRNiomo96KQXpxwqAzZLw+VDXfJMypwDMAVZe/SqzSJnFEtZxjdxaEo3VLcZ1mnbIL0vS7D6iFeYutF9kF231165qGd3k2tgymNMMpY7oYKjS11Y6JqWDU0WE5hjS2X35iG6mE=</D></RSAKeyValue>");
string data2Decrypt = "BaB21vY+RD/jiY3AAsb269fIWTEH38s0xLUfJ7CoVUgaQ6vYzB0tiJ1Ag9HNEdCcuZdGchhqnms8jpsqsHC1iKrz6QCLsgUU7VNWDfQqZYR6Rl/GwR0biK2STnOL+g06f/JUdixHOHOgROify1m8qppYo5plpOVMqYFzEMREMkM=";
byte[] encyrptedBytes = Convert.FromBase64String(data2Decrypt);
byte[] plain = rsa1.Decrypt(encyrptedBytes, false);
string decryptedString = System.Text.Encoding.UTF8.GetString(plain);
Console.WriteLine("SALIDA: " + decryptedString);
Now I want to do the opposite... But I get some errors like (the size of the key should be 128 bytes... etc) How should I do it?
Here I add the current non working code:
.NET
public string Encrypt(string text)
{
const int PROVIDER_RSA_FULL = 1;
const string CONTAINER_NAME = "Tracker";
CspParameters cspParams;
cspParams = new CspParameters(PROVIDER_RSA_FULL);
cspParams.KeyContainerName = CONTAINER_NAME;
RSACryptoServiceProvider rsa1 = new RSACryptoServiceProvider(cspParams);
rsa1.FromXmlString("<RSAKeyValue><Modulus>2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=</Modulus><Exponent>AQAB</Exponent><P>92jJJyzFBSx6gL4Y1YpALmc5CNjoE/wETjqb3ci2v0+3rZWvJKmKy1ZEdlXpyuvXVksJ6cMdUpNAkMknUk9pTQ==</P><Q>4kxkABZOXyDLryYGCGY0b8N0FIdu5BTCFDYEdcatxl/f7ZGDS1NgHJpUWxkVXFfHy2Y/GuDOIbpcwlsO739H+w==</Q><DP>5bNFvrdUHF+VRN45VFjNCcgQLeSkY5mBrdfASoNFGA29LM5iE5nNIMfxPCS7sQiRnq6Af6YFHVtVgJchiMvtqQ==</DP><DQ>j+ng1qVY5epnXlWiFIla45C7K6sNfIMvAcdwgq39KWEjeWPGyYqWXtpOtzh2eylf6Bx4GVHKBW0NPJTIJMsfLQ==</DQ><InverseQ>8uu0dfPVDqB2qFM1Vdi8hl+2uZtN7gjT2co1cEWy29HVYBZD0k9KKCf2PbkeuSfpgFpE70wW5Hrp8V7l/SwSOw==</InverseQ><D>MM/c18zroJ2Iqi9s5/asvUBF3pjO3NSEbFjFpP/NT6WdKimvECWPz2xT6NlV0Vc6tQaAAmtn7Bt+HPhfVdrA4/ysYVe3/6TWkPjW+bvAhMWu/ZqISx11/jPYSGD9g3ZXgUiqcQM8UbOjlswoq4fpheEXTB0xdVutDLpO3qgHN6k=</D></RSAKeyValue>");
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] textBytes = encoding.GetBytes(text);
byte[] encryptedOutput = rsa1.Encrypt(textBytes, false);
string outputB64 = Convert.ToBase64String(encryptedOutput);
Console.WriteLine(outputB64);
return outputB64;
}
Java
public static String Decrypt(String encodedString) throws IllegalBlockSizeException, UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, BadPaddingException
{
byte[] modulusBytes = Base64.decode("2rRVVVFJRbH/wAPDtnwZwu+nxU+AZ6uXxh/sW+AMCBogg7vndZsnRiHoLttYYPqOyOhfgaBOQogrIfrKL4lipK4m52SBzw/FfcM9DsKs/rYR83tBLiIAfgdnVjF27tZID+HJMFTiI30mALjr7+tfp+2lIACXA1RIKTk7S9pDmX8=");
byte[] exponentBytes = Base64.decode("AQAB");
BigInteger modulus = new BigInteger(1, modulusBytes );
BigInteger exponent = new BigInteger(1, exponentBytes);
RSAPrivateKeySpec rsaPrivKey = new RSAPrivateKeySpec(modulus, exponent);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey privKey = fact.generatePrivate(rsaPrivKey);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
}
The last few lines of your Java decrypt code do not make sense. These lines are:
byte[] base64String = Base64.decode(encodedString);
byte[] plainBytes = new String(base64String).getBytes("UTF-8");
byte[] cipherData = cipher.doFinal(plainBytes);
System.out.println(cipherData);
return cipherData.toString();
You have to reverse the order of the steps you used to encrypt in .NET. First, you should Base64 decode the encoded string to get the cipher bytes. You did that, but you mislabeled the result as base64String. You probably should call this result cipherData. Second, you need to decrypt cipherData to get plain text. Third, you should create a string from plainbytes using the two-arg String constructor with the Charset for the second argument. Here is what the code should look like, or close to it.
byte[] cipherData = Base64.decode(encodedString);
byte[] plainBytes = cipher.doFinal(cipherData);
return new String(plainBytes, "UTF-8");
Finally, in Java every object has a toString() method but it doesn't always do what you want. For arrays the toString() method simply returns a representation of object id for that array, sort of the JVM equivalent of a memory address.
EDIT:
I missed that you are also using the wrong key in your decrypt code. Your are using the RSA public key, but you must instead use the RSA private key.
Here is the answer I couldn't post yesterday, related to the first answer to my post.
Well, I have tested the code and I have some problems. I have tried not to change anything unless it was completely necessary.
First I get an error here:
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
The "Entrust" crypto provider is not recognized... So I left just the first parameter. Then I get this error:
javax.crypto.BadPaddingException: Data must start with zero
I have tried through a WebService written in .NET which returns always byte arrays. Maybe there is some kind of problem in the translation. I know that I have to use Base64 numbers and (if I don't use AES) I have to break my Strings into pieces with the size of 128 bytes (limited by the RSA key).
I am still working on the problem to realize why I could encrypt in Java and decrypt in .NET but not the opposite.
Thanks again for your help!!
As you requested are hare some code snippets. RSA keys are from x509 certs.
Java RSA/AES:
// symmetric algorithm for data encryption
final String ALGORITHM = "AES";
// Padding for symmetric algorithm
final String PADDING_MODE = "/CBC/PKCS5Padding";
// character encoding
final String CHAR_ENCODING = "UTF-8";
// provider for the crypto
final String CRYPTO_PROVIDER = "Entrust";
// RSA algorithm used to encrypt symmetric key
final String RSA_ALGORITHM = "RSA/ECB/PKCS1Padding";
// symmetric key size (128, 192, 256) if using 192+ you must have the Java
// Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files
// installed
int AES_KEY_SIZE = 256;
private byte[] encryptWithRSA(byte[] aesKey, X509Certificate cert)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// get the public key from the encryption certificate to encrypt with
PublicKey pubKey = cert.getPublicKey();
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM);
// set the cipher to use the public key
rsaCipher.init(Cipher.ENCRYPT_MODE, pubKey);
// encrypt the aesKey
return rsaCipher.doFinal(aesKey);
}
private AESEncryptedContents encryptWithAes(byte[] dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException,
BadPaddingException, NoSuchProviderException {
// get the symmetric key generator
KeyGenerator keyGen = KeyGenerator.getInstance(ALGORITHM);
keyGen.init(AES_KEY_SIZE); // set the key size
// generate the key
SecretKey skey = keyGen.generateKey();
// convert to binary
byte[] rawAesKey = skey.getEncoded();
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(rawAesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to encrypt mode, with the generated key
aesCipher.init(Cipher.ENCRYPT_MODE, skeySpec);
// get the initialization vector being used (to be returned)
byte[] aesIV = aesCipher.getIV();
// encrypt the data
byte[] encryptedData = aesCipher.doFinal(dataToEncrypt);
// package the aes key, IV, and encrypted data and return them
return new AESEncryptedContents(rawAesKey, aesIV, encryptedData);
}
private byte[] decryptWithAES(byte[] aesKey, byte[] aesIV,
byte[] encryptedData) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException, UnsupportedEncodingException,
NoSuchProviderException {
// initialize the secret key with the appropriate algorithm
SecretKeySpec skeySpec = new SecretKeySpec(aesKey, ALGORITHM);
// get an instance of the symmetric cipher
Cipher aesCipher = Cipher.getInstance(ALGORITHM + PADDING_MODE,
CRYPTO_PROVIDER);
// set it to decrypt mode with the AES key, and IV
aesCipher.init(Cipher.DECRYPT_MODE, skeySpec,
new IvParameterSpec(aesIV));
// decrypt and return the data
byte[] decryptedData = aesCipher.doFinal(encryptedData);
return decryptedData;
}
private byte[] decryptWithRSA(byte[] encryptedAesKey, PrivateKey privKey)
throws IllegalBlockSizeException, BadPaddingException,
InvalidKeyException, NoSuchAlgorithmException,
NoSuchPaddingException, NoSuchProviderException {
// get an instance of the RSA Cipher
Cipher rsaCipher = Cipher.getInstance(RSA_ALGORITHM, CRYPTO_PROVIDER);
// set the cipher to use the public key
rsaCipher.init(Cipher.DECRYPT_MODE, privKey);
// encrypt the aesKey
return rsaCipher.doFinal(encryptedAesKey);
}
C# .Net:
public byte[] encryptData(byte[] data, out byte[] encryptedAesKey, out byte[] aesIV) {
if (data == null)
throw new ArgumentNullException("data");
byte[] encryptedData; // data to return
// begin AES key generation
RijndaelManaged aesAlg = new RijndaelManaged();
aesAlg.KeySize = AES_KEY_SIZE;
aesAlg.GenerateKey();
aesAlg.GenerateIV();
aesAlg.Mode = CipherMode.CBC;
aesAlg.Padding = PaddingMode.PKCS7;
// aes Key to be encrypted
byte[] aesKey = aesAlg.Key;
// aes IV that is passed back by reference
aesIV = aesAlg.IV;
//get a new RSA crypto service provider to encrypt the AES key with the certificates public key
using (RSACryptoServiceProvider rsaCSP = new RSACryptoServiceProvider())
{
//add the certificates public key to the RSA crypto provider
rsaCSP.FromXmlString(encryptionCertificate.PublicKey.Key.ToXmlString(false));
//encrypt AES key with RSA Public key
//passed back by reference
encryptedAesKey = rsaCSP.Encrypt(aesKey, false);
//get an aes encryptor instance
ICryptoTransform aesEncryptor = aesAlg.CreateEncryptor();
encryptedData = encryptWithAes(aesEncryptor, data);
}
if (encryptedData == null)
throw new CryptographicException(
"Fatal error while encrypting with AES");
return encryptedData;
}
private byte[] encryptWithAes(ICryptoTransform aesEncryptor, byte[] data) {
MemoryStream memStream = null; // stream to write encrypted data to
CryptoStream cryptoStream = null; // crypto stream to encrypted data
try {
memStream = new MemoryStream();
// initiate crypto stream telling it to write the encrypted data to
// the memory stream
cryptoStream = new CryptoStream(memStream, aesEncryptor,
CryptoStreamMode.Write);
// write the data to the memory stream
cryptoStream.Write(data, 0, data.Length);
} catch (Exception ee) {
// rethrow
throw new Exception("Error while encrypting with AES: ", ee);
} finally {
// close 'em
if (cryptoStream != null)
cryptoStream.Close();
if (memStream != null)
memStream.Close();
}
// return the encrypted data
return memStream.ToArray();
}
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..