Sunday, March 1, 2015

RSA Encryption

After I wrote about AES as an example for a symmetric encryption, today I want to post about RSA as an example for asymmetric encryption. Asymmetric cryptography is also known as public-key crytography. This is due to the fact, that not one key, like for symmetric algorithms, is used for encryption and decryption, but two: A public one is used for encryption and a private one for decryption. The public key can be distributed freely and has to be know to the sender. He encrypts using the public key of the recipient and sends the message to the recipient. The recipient then can decrypt it with the corresponding private key, so this key should not be passed on.
This directly shows a major advantage of asymmetric encryption: For symmetrical algorithms the participants have to agree upon a key, for example one picks a key and sends it to the other. But if this is done unencrypted, this can also be intercepted and we have not gained anything. For asymmetric algorithms this step is not needed! We just have to make our public key available (still this has to be done in an authenticated way!). We never have to pass on the private key and can lock it away somewhere safe.
One disadvantage of asymmetric algorithms is their speed, they are mostly significantly slower than symmetric ones.
Asymmetric cryphtography is based on so called one-way functions, for which one direction is easy to calculate, but the other hard.

Here I want to describe the implemention of the RSA cryptosystem in C#. RSA is based on the supposed hardness of prime factorization. For the key creation 2 prime numbers p and q are chosen and their product n is calculated. Calculate φ(n) = (p - 1)(q - 1) and choose e relatively prime to φ(n). Then calculate the multiplicative inverse d of e relative to φ(n). The public key then is (e, n) and the private one (d, n). The encrypted message is then calculated as c = m^e mod n, decryption is done by m = c^d mod n.

But enough of the theory, let us come to the code. In C# for this we have the class RSACryptoServiceProvider. The usage of this though is somewhat different than when using code for symmetric encrpytion, due to its different mode of operation: When using RSA, first a public / private key pair has to be created. Then we pass the public key to our communication partner, so he can encrypt for us. Finally we decrypt with our private key.

When creating a new instance of the class RSACryptoServiceProvider automatically a new key pair is created, in the constructor we optionally can set its size etc. With the function ExportParameters() we can export the key (amongst others). This function expects a Boolean parameter, which determines, whether we want to export also the private parameters. We do this when sending them to our decrypting function. We choose the other variant when sending the public key to our communication partner. Via ImportParameters() an RSACryptoServiceProvider instance can import the parameters.

And here the code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.Security.Cryptography;

namespace RSA2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            byte[] dataToEncrypt = System.Text.Encoding.Unicode.GetBytes("This is a secret.");
            byte[] encryptedData;
            byte[] decryptedData;

            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

            encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false));

            MessageBox.Show("Encrypted: " + System.Text.Encoding.Unicode.GetString(encryptedData));

            decryptedData = RSADecrypt(encryptedData, RSA.ExportParameters(true));

            MessageBox.Show("Decrypted: " + System.Text.Encoding.Unicode.GetString(decryptedData));
        }


        static public byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo)
        {
            byte[] encryptedData;

            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(RSAKeyInfo);

            encryptedData = RSA.Encrypt(DataToEncrypt, false);

            return encryptedData;
        }

        static public byte[] RSADecrypt(byte[] DataToDecrypt, RSAParameters RSAKeyInfo)
        {
            byte[] decryptedData;

            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.ImportParameters(RSAKeyInfo);

            decryptedData = RSA.Decrypt(DataToDecrypt, false);

            return decryptedData;
        }
    }
}

No comments:

Post a Comment