RSA in C# does not produce same encrypted string for specific keys?
Asked Answered
B

2

3

I have a requirement, where I need to encrypt my connection string in one application and decrypt it in another. With this in mind, I save the public key and private keys in App.Config of the application respectively.

Now, shouldn't RSA should give me same encrypted string with same keys which I use?

I get different encrypted strings all the time, with same keys used.!! Please help me to clear the confusion. I am not understanding how I can solve this problem, that I get BAD Data exception if I use the saved encrypted string, as every time the encryption gives me different encrypted strings.

Here is my code:

private string connecString;
private RSACryptoServiceProvider rsaEncryptDecrypt;

public EncryptAndDecrypt(string connecString)
{
    this.connecString = connecString;
    this.rsaEncryptDecrypt = new RSACryptoServiceProvider(4096);
}

public string EncryptTheConnecString(string publicKeyValue)
{
    byte[] encryptedData;
    rsaEncryptDecrypt.FromXmlString(publicKeyValue);

    byte[] message = Encoding.UTF8.GetBytes(connecString);
    encryptedData = rsaEncryptDecrypt.Encrypt(message, false);

    return Convert.ToBase64String(encryptedData);
}

public string DecryptTheConnecString(string privateKeyValue, string encrystr)
{
    byte[] decryptedData;
    rsaEncryptDecrypt.FromXmlString(privateKeyValue);

    byte[] message = Convert.FromBase64String(encrystr);
    decryptedData = rsaEncryptDecrypt.Decrypt(message, false);

    return Encoding.UTF8.GetString((decryptedData));
}

Thank you in advance.

Update 1: I used

UnicodeEncoding ByteConverter = new UnicodeEncoding();
ByteConverter.GetBytes("data to encrypt");
//Which is not Connection string but a small test str

Still I see that the encrypted data is changing everytime. But the Bad Data error is no more seen. Yet I cannot use UTF16(UnicodeEncoding) over Encoding.UTF8 because it cannot encrypt the huge string like connection string and throws an exception:

 CryptographicException: Key not valid for use in specified state.

Update 2:

I could solve the problem of bad data by using UTF8Encoding ByteConverter = new UTF8Encoding(); and then doing ByteConverter .GetString("HUGE STRING");

Barrio answered 28/2, 2012 at 15:15 Comment(2)
re: Update 2, Encoding.UTF8 is an UTF8Encoding object (.Net 4.5)Collage
Never write new RSACryptoServiceProvider(4096); in your code, it's a bug. ALWAYS RSA.Create() ...Iamb
A
6

It can happen because of Random Padding.

Accuracy answered 29/2, 2012 at 4:41 Comment(2)
Hmmm, oh okay.. will look out about this one. !Barrio
Great, Just now found this AnswerBarrio
N
2

In general the answer to your question is yes, it should always produce the same result if the same parameters are given.

The best way to tackle these issues is to stay as close to the best practice code as possible, currently you a using the crypto provider slightly different than the framework docs propose, see the following:

static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
{
    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;
}

This is an excerpt from the official MSDN doc:
http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.aspx

First try and adopt the best practice and then see if this issue still comes up.

Nickelplate answered 28/2, 2012 at 15:29 Comment(3)
The very example you gave, I tried it before I came with this solution. But I get this error: CryptographicException Key not valid for use in specified state. Because my connecString is huge than their text. So I convert it to Encoding.UTF8.GetBytes(connecString); rather than ByteConverter.GetBytes(connecString);Barrio
@NagarajTantri the randomness you might experience comes from the padding as @zespri described and that's the reason you can disable the padding in the default implementation code, simply make set the parameter DoOAEPPadding = falseNickelplate
Using RSA without padding is insecure. crypto.stackexchange.com/questions/1448/…Iamb

© 2022 - 2024 — McMap. All rights reserved.