11
votes

I am creating a C# Winforms application which POSTs data to a server over HTTPS.

The login mechanism is supposed to be like this:

  1. I send the username to the server, it responds with rsa-modulus and rsa-exponent

  2. I encrypt the password using these given parameters and send username + password to the server for authentication

I have tried the RSACryptoServiceProvider class, but I cannot find samples or anything said on how we can do the encryption using a given modulus and exponent?.

I think that without specifying any values, its doing default encryption parameters..

So if anybody has done this before, can they give me some hints please? thanks

UPDATE: according to the suggestion by Mr. Carsten Konig, . I have tried to do it with RSAParameters and RSA.ImportParameters, but it returns a "BAD DATA" error with cryptographic exception. My code is given below.

I have also tried RSA.FromXmlString(mykey); (where mykey contains an xml string with modulus and exp) but I also get a "BAD DATA" errror with cryptographic exception... any idea anybody? or if its some microsoft bug, can anyone suggest some other decent library to do this easily?

RSAParameters rsaparam = new RSAParameters(); 
rsaparam.Modulus = modbytes; 
rsaparam.Exponent = expbytes; 
RSACryptoServiceProvider RSA = new RSACryptoServiceProvider() ; 
RSA.ImportParameters(rsaparam); 
byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false)
3

3 Answers

8
votes

You can do this by using the RSACryptoServiceProvider.Encrypt method. You will also need to use the RSACryptoServiceProvider.ImportParameters method and pass it an RSAParameters structure (this is where you set the exponent, modulus, etc).

Please have a look at the documentation in the link for the RSAParameters - it's very well documented what parameter you have to pass for what structure-field - should be no problem if you now the algorithm.

EDIT: here is the example straight from the MSDN-site:

class RSACSPSample
{

    static void Main()
    {
        try
        {       //initialze the byte arrays to the public key information.
            byte[] PublicKey = {214,46,220,83,160,73,40,39,201,155,19,202,3,11,191,178,56,
                                   74,90,36,248,103,18,144,170,163,145,87,54,61,34,220,222,
                                   207,137,149,173,14,92,120,206,222,158,28,40,24,30,16,175,
                                   108,128,35,230,118,40,121,113,125,216,130,11,24,90,48,194,
                                   240,105,44,76,34,57,249,228,125,80,38,9,136,29,117,207,139,
                                   168,181,85,137,126,10,126,242,120,247,121,8,100,12,201,171,
                                   38,226,193,180,190,117,177,87,143,242,213,11,44,180,113,93,
                                   106,99,179,68,175,211,164,116,64,148,226,254,172,147};

            byte[] Exponent = {1,0,1};

            //Values to store encrypted symmetric keys.
            byte[] EncryptedSymmetricKey;
            byte[] EncryptedSymmetricIV;

            //Create a new instance of RSACryptoServiceProvider.
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

            //Create a new instance of RSAParameters.
            RSAParameters RSAKeyInfo = new RSAParameters();

            //Set RSAKeyInfo to the public key values. 
            RSAKeyInfo.Modulus = PublicKey;
            RSAKeyInfo.Exponent = Exponent;

            //Import key parameters into RSA.
            RSA.ImportParameters(RSAKeyInfo);

            //Create a new instance of the RijndaelManaged class.
            RijndaelManaged RM = new RijndaelManaged();

            //Encrypt the symmetric key and IV.
            EncryptedSymmetricKey = RSA.Encrypt(RM.Key, false);
            EncryptedSymmetricIV = RSA.Encrypt(RM.IV, false);

            Console.WriteLine("RijndaelManaged Key and IV have been encrypted with RSACryptoServiceProvider."); 

        }
        //Catch and display a CryptographicException  
        //to the console.
        catch(CryptographicException e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

Please note that only the key/iv gets encrypted - not arbitrary bytes - the length of those bytes is important too!

The allowed length is described in MSDN an depends on the OS!

3
votes

If you are using RSACryptoServiceProvider.ToXmlString to export the modulus and exponent that the server sends, you need to use Convert.FromBase64String.

    public RSAParameters SetPublicKey(string modulus, string exponent)
    {
        RSAParameters result = new RSAParameters();
        result.Modulus = Convert.FromBase64String(modulus);
        result.Exponent = Convert.FromBase64String(exponent);

        return result;
    }
0
votes

One additional hint that was very useful for me:

In this line,

//Set RSAKeyInfo to the public key values. 
SAKeyInfo.Modulus = PublicKey;

PublicKey can also be a direct, straightforward, array of bytes that you can get from the "Public Key" field of a X509 Certificate (directly).