I am starting to use encryption and decryption in my web service. I am using the RSACryptoServiceProvider and when using the Encrypt & Decrypt methods, I have no problem.
However, as soon as I try to use the SignData method with new SHA1CryptoServiceProvider() as encryption method, I am unable to recover the original data. I am only able to verify them.
Is it really not possible to retrieve the signed data? If so, what is the purpose of the whole signing process? And is there another possibility how to encrypt data by a certain algorithm?
EDIT: I am posting the code, which is just an altered example from MSDN
static void Main()
{
try
{
//Create a UnicodeEncoder to convert between byte array and string.
ASCIIEncoding ByteConverter = new ASCIIEncoding();
string dataString = "Data to Encrypt";
//Create byte arrays to hold original, encrypted, and decrypted data.
byte[] dataToEncrypt = ByteConverter.GetBytes(dataString);
byte[] encryptedData;
byte[] signedData;
byte[] decryptedData;
byte[] unsignedData;
var fileName = ConfigurationManager.AppSettings["certificate"];
var password = ConfigurationManager.AppSettings["password"];
var certificate = new X509Certificate2(fileName, password);
//Create a new instance of the RSACryptoServiceProvider class
// and automatically create a new key-pair.
RSACryptoServiceProvider RSAalg = (RSACryptoServiceProvider)certificate.PrivateKey;
//RSAPKCS1SignatureDeformatter def = (RSAPKCS1SignatureDeformatter)certificate.PrivateKey;
//Display the origianl data to the console.
Console.WriteLine("Original Data: {0}", dataString);
//Encrypt the byte array and specify no OAEP padding.
//OAEP padding is only available on Microsoft Windows XP or
//later.
encryptedData = RSAalg.Encrypt(dataToEncrypt, false);
signedData = RSAalg.SignData(dataToEncrypt, new SHA1CryptoServiceProvider());
//Display the encrypted data to the console.
Console.WriteLine("Encrypted Data: {0}", ByteConverter.GetString(encryptedData));
Console.WriteLine("Signed Data: {0}", ByteConverter.GetString(signedData));
//Pass the data to ENCRYPT and boolean flag specifying
//no OAEP padding.
decryptedData = RSAalg.Decrypt(encryptedData, false);
//In the next line I get the error of wrong data
unsignedData = RSAalg.Decrypt(signedData, false);
//Display the decrypted plaintext to the console.
Console.WriteLine("Decrypted plaintext: {0}", ByteConverter.GetString(decryptedData));
Console.WriteLine("Unsigned plaintext: {0}", ByteConverter.GetString(unsignedData));
}
catch (CryptographicException e)
{
//Catch this exception in case the encryption did
//not succeed.
Console.WriteLine(e.Message);
}
Console.Read();
}
SHA1 is a hash function, so you cant compute a message that has a given hash. In other words, you cant sign/unsign the message, you only can sign and verify it.
Related
I was trying to decrypt the encrypted data which was in string format, because of this i have to execute the Encoding function 2 times which leads me to this error The data to be decrypted exceeds the maximum for this modulus of 256 bytes. However if i pass in the encrypted data in bytes format, the decryption works.
Here is the issue, i want user to copy and paste the encrypted data into a Textbox(string format) and decrypt using the information from the TextBox.
Please advice me on how to fix this problem.
Here is the example of my concept, the first Textbox is where user input the encrypted data
Here is my code
public static byte[] RSADecrypt2(byte[] ciphertext, string srcKey)
{
byte[] decryptedData;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.FromXmlString(srcKey);
decryptedData = rsa.Decrypt(ciphertext, true);
rsa.Dispose();
return decryptedData;
}
private void RSADecrypt_Click(object sender, EventArgs e)
{
byte[] encryption = Encoding.Unicode.GetBytes(passBox.Text);
string privateKey = rsaBoxPrivate.Text;
byte[] decryption = RSADecrypt2(encryption, privateKey);
decryptedBox.Text = Encoding.Unicode.GetString(decryption);
}
I want encrypt and decrypt data using RSACryptoServiceProvider in c# in wp8 project. I am creating asymmetric keys as :
CspParameters parameters = new CspParameters();
parameters.KeyContainerName = "MyContainer";
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(parameters);
Now I want do encrypt data. I am doing:
CspParameters parameters = new CspParameters();
parameters.KeyContainerName = "MyContainer";
RSACryptoServiceProvider obj = new RSACryptoServiceProvider(parameters);
byte[] a = Generic.RSAEncrypt(ByteConverter.GetBytes(s[0]),
obj.ExportParameters(false), false);
public static byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo,
bool DoOAEPPadding)
{
try {
byte[] encryptedData;
//Create a new instance of RSACryptoServiceProvider.
CspParameters parameters = new CspParameters();
parameters.KeyContainerName = "TCSContainer";
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(parameters))
{
//Import the RSA Key information. This only needs
//to include 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 (CryptographicException e) {
//Catch and display a CryptographicException
//to the console.
//Console.WriteLine(e.Message);
return null;
}
}
Now I am getting exception while encypting:
RSA.EncryptSystem.Security.Cryptography.CryptographicException : Bad length in RSACryptoserviceProvider.
Stacktrace is:
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.RSACryptoServiceProvider.EncryptKey(SafeKeyHandle pKeyContext, Byte[] pbKey, Int32 cbKey, Boolean fOAEP, ObjectHandleOnStack ohRetEncryptedKey)
at System.Security.Cryptography.RSACryptoServiceProvider.Encrypt(Byte[] rgb, Boolean fOAEP)
at WindowsAppmart.Generic.RSAEncrypt(Byte[] DataToEncrypt, RSAParameters RSAKeyInfo, Boolean DoOAEPPadding)
and message is Bad Length.
I am not getting where can I go wrong?
RSA is only meant to be used for encrypting small amounts of data. The exact amount you can encrypt depends on the key length + the amount used by the padding. A 1024 bit key would allow for a bit above 100 bytes.
Since RSA is quite slow, the usual way to encrypt large messages is using hybrid encryption. In hybrid encryption you use a fast symmetric encryption algorithm (like AES) for encrypting the data with a random key. The random key is then encrypted with RSA and send along with the symmetric key encrypted data.
This indicates that the amound of data you are trying to encrypt is too long. You should encrypt it in smaller bulks.
I have below code to encrypt and decrypt the message in c#. when i am trying to run it is giving an exception ie "The data to be decrypted exceeds the maximum for this modulus of 256 bytes"
public static void Main(string[] args)
{
X509Certificate2 cert = new X509Certificate2(#"C:\Data\ABC-rsa-public-key-certificate.cer");
string encryptedText = EncrypIt("Hello", cert);
string decryptedText = DecrptIt(encryptedText, cert);
System.Console.WriteLine(decryptedText);
}
public static string EncrypIt(string inputString, X509Certificate2 cert)
{
RSACryptoServiceProvider publicKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] plainBytes = Encoding.UTF8.GetBytes(inputString);
byte[] encryptedBytes = publicKey.Encrypt(plainBytes, false);
string encryptedText = Encoding.UTF8.GetString(encryptedBytes);
return encryptedText;
}
public static string DecrptIt(string encryptedText, X509Certificate2 cert)
{
RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
byte[] encryptedBytes = Encoding.UTF8.GetBytes(encryptedText);
byte[] decryptedBytes = privateKey.Decrypt(encryptedBytes, false);
string decryptedText = Encoding.UTF8.GetString(decryptedBytes);
return decryptedText;
}
Several problems:
RSA by default only encrypts one block. It's not suitable for long messages. You shouldn't encrypt the message itself with RSA. Generate a random AES key and encrypt the key with RSA and the actual message with AES.
You must use a binary safe encoding such as Hex or Base64 for the ciphertext. Using UTF-8 corrupts the data since it doesn't allow arbitrary byte sequences.
UTF-8 is designed to encode text, so it's fine for your plaintext.
Use OAEP, the old 1.5 padding mode is not secure. i.e. pass true as second parameter to Encrypt/Decrypt. (Technically it's possible to use it securely, but it's tricky and I wouldn't recommend it)
As a further note, once you use AES, there are some more pitfalls: 1) Use a MAC in an encrypt-then-mac scheme, else active attacks including padding-oracles will break your code 2) Use a random IV that's different for each message
RSA should not be used to encrypt this kind of data. You should be encrypting your data with a symmetric key like AES, then encrypting the symmetric key with RSA.
I using RSA(1024) to encrypt/decrypt strings. The encryption is implemented using public key and is written in C#, and the decryption is implementation by c. I encrypt the string:
86afaecb-c211-4d55-8e90-2b715d6d64b9
and write the encrypted data to a file. Then, I using openssl api to read the encrypted data from the file and decrypt it. However, I got the output as:
86afaecb-c211-4d55-8e90-2b715d6d64b9oeheBjQ8fo1AmDnor1D3BLuPyq9wJBAOV+M/WVNYzYr
PJBKoskOj+4LaNpT+SpkfK81nsnQEbHbjgao4eHNU+PmWl9
It seems that there are some trashy padding at the end of original string. Why It Occurs? And how to solve the problem?
Some code snippet is shown below:
// Encrypt
{
string plainData = “86afaecb-c211-4d55-8e90-2b715d6d64b9”;
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
rsa.ImportParameters(paraPub);
byte[] testData = Encoding.UTF8.GetBytes(plainData);
byte[] encryptedData = rsa.Encrypt(testData, true);
FileStream pFileStream = null;
string fileName = "encryptedData.dat";
pFileStream = new FileStream(fileName, FileMode.OpenOrCreate);
pFileStream.Write(encryptedData, 0, encryptedData.Length);
...
}
// Decrypt
{
char *encrypt = malloc(RSA_size(privateKey));
FILE *out = fopen("encryptedData.dat", "r");
int encrypt_len = fread(encrypt, sizeof(*encrypt), RSA_size(privateKey), out);
fclose(out);
decrypt = malloc(encrypt_len);
if(RSA_private_decrypt(encrypt_len,
(unsigned char*)encrypt,
(unsigned char*)decrypt,
privateKey, RSA_PKCS1_OAEP_PADDING) == -1) {
// error handle
}
printf("Decrypted message: %s\n", decrypt);
}
I solve the problem by initializing the decrypt using "memset(decrypt, 0, encrypt_len);" after "decrypt = malloc(encrypt_len);". Thx everyone.
The issue is that you should use the decrypted size instead of directly treating the output of the decryption as a null terminated string.
RSA_private_decrypt() returns the size of the recovered plaintext.
I am developing an application in java for a mobile platform. The program uses data from a Windows C# application which encrypts passwords in an online database which the mobile app will use.
The mobile app needs to connect to the database and retrieve the encrypted string from the database and decrypt it.
I have the decryption working fine using the following code
public String decrypt(String encryptedPassword)
{
String plainPassword = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
plainPassword = new String(encoded);
}
catch (Exception ex)
{
Log.d("Decryption Error", ex.toString());
}
return plainPassword;
}
The decryption works absolutely fine so I have used the same code from the decryption for the encryption but changed the cipher mode from decrypt to encrypt. However, when I print to the console the encrypted password it prints a load of rubbish which shows no resemblance the string that should be stored in the database.
I have used the following code in order to do the encryption
public String encrypt(String plainPasword)
{
String password = "";
try
{
SecretKeySpec key = new SecretKeySpec("hcxilkqbbhczfeultgbskdmaunivmfuo".getBytes("US-ASCII"), "AES");
IvParameterSpec iv = new IvParameterSpec("ryojvlzmdalyglrj".getBytes("US_ASCII"));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
password = new String(encoded);
}
catch (Exception ex)
{
Log.d("Encryption Error", ex.toString());
}
return password;
}
Thanks for any help you can give me
In the decryption function you are calling
byte[] encoded = cipher.doFinal(Base64.decodeBase64(encryptedPassword.getBytes()));
so you are converting ASCII bytes to Base64 bytes, then decrypting them.
Wouldn't you do the same in the reverse, when you actually call only
byte[] encoded = cipher.doFinal(plainPasword.getBytes());
You also are creating new String() from byte[] array without specifying encoding, that uses platform's default encoding, not ASCII. That might break stuff too.
If you look at the bytes returned by cipher.doFinal() that's supposed to be gibberish, don't they have any resemblance to the expected data?