Home / Cryptography / Asymmetric Encryption – RSA

Asymmetric Encryption – RSA

The main problem with symmetric encryption is that of securely sharing keys. For a recipient to decrypt a message, they need the same key as the sender, and this exchange of keys can be very difficult to do securely. A good solution to this problem is to use asymmetric cryptography (RSA), which is also referred to as public key cryptography. With public key cryptography you have two keys. A public key which anyone can know, and a private key which only the recipient of a message knows. These keys are mathematically linked.

A sender uses the public key to encrypt a message and the recipient uses their private key to decrypt the message. The term “asymmetric” is used because this method uses two different linked keys that perform inverse operations from each other whereas symmetric cryptography uses the same key to perform both operations.

It is very easy to generate both the public and private key pair, but the power of asymmetric cryptography comes from the fact it is impossible for a private key to be determined from its corresponding public key. It is only the private key that needs to be kept secret in the key pair.

RSA

RSA is public key encryption technology developed by RSA Security LLC. The acronym stands for Rivest, Shamir, and Adelman, the inventors of the technique.

This algorithm is based on the fact that there is no efficient way to factor very large numbers. Deducing the key, therefore, requires an extraordinary amount of computer processing power and time. The algorithm has become the de facto standard for industrial-strength encryption, especially for data sent over the Internet.

There is a drawback to the RSA algorithm, though. You can only encrypt data that is smaller than the size of the key, so this makes this type of encryption quite limited. It is more common to use this algorithm to encrypt a randomly generated, symmetric AES key. This means you can send the RSA-encrypted AES key safely to a recipient and then use AES with that key to encrypt your data.

In the following examples, we will look at three example implementations of RSA in .NET. The first uses an in-memory set of keys, the second uses keys that are stored in XML files, and the final example stores its keys in the Crypto Service Provider key store.

Example with In-memory Keys

In the following example we have a class called RSAWithRSAParameterKey. This class is a self-contained implementation that will allow you to generate a public/private key pair, and use those keys to encrypt and decrypt some data.

public class RSAWithRSAParameterKey

{

private RSAParameters publicKey;

private RSAParameters privateKey;

public void AssignNewKey()

{

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

publicKey = rsa.ExportParameters(false);

privateKey = rsa.ExportParameters(true);

}

}

public byte[] Encrypt(byte[] data)

{

byte[] cipherbytes;

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

rsa.ImportParameters(publicKey);

cipherbytes = rsa.Encrypt(data, true);

}

return cipherbytes;

}

public byte[] Decrypt(byte[] data)

{

byte[] plain;

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

rsa.ImportParameters(privateKey);

plain = rsa.Decrypt(dataToEncrypt, true);

}

return plain;

}

}

The first method is AssignNewKey(). This method will generate both a public and a private key and store them in two private properties, publicKey and privateKey. These two properties represent the raw key data expressed as byte arrays. With the key data stored in memory, you can save them to a binary file or do with them as you see fit. Keep in mind that the private key is the key you need to keep secret and the public key is the key you give out to people who want to send encrypted data to you with the RSA algorithm.

The second method is the EncryptData method. This method requires a byte array of the data you intend to encrypt. The RSACryptoServiceProvider object is then created and the size of the key is passed in. In this case, we are using a 2,048-bit key which is the recommended minimum key length to use.

Once this object has been created, the PersistKeyInCsp flag is set to false. This flag is set to true when you want to persist your key in a key container. The PersistKeyInCsp property is automatically set to true when you specify a key container name in a CspParameters object and use it to initialize an RSACryptoServiceProvider object. You can also specify a container name by using the KeyContainerName field. If you set the PersistKeyInCsp property to true without initializing the RSACryptoServiceProvider object with a CspParameters object, a random key container name prepended with “CLR” is created. In this example, we are not using a key container.

Next, the public key is imported into the RSACryptoServiceProvider instance. At this point, all that’s necessary to encrypt some data is pass in your raw byte array of data. The second parameter is a Boolean to specify Optimal Asymmetric Encryption Padding (OAEP). OAEP is a scheme that improves the resistance against chosen ciphertext attacks.

Example with XML-based Keys

In the following example, we have a class called RSAWithXMLKey. This class is a self-contained implementation that will allow you to generate a public/private key pair and use those keys to encrypt and decrypt some data.

public class RsaWithXMLKey

{

public void AssignNewKey(string publicKeyPath, string privateKeyPath)

{

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

if (File.Exists(privateKeyPath))

{

File.Delete(privateKeyPath);

}

if (File.Exists(publicKeyPath))

{

File.Delete(publicKeyPath);

}

var publicKeyfolder = Path.GetDirectoryName(publicKeyPath);

var privateKeyfolder = Path.GetDirectoryName(privateKeyPath);

if (!Directory.Exists(publicKeyfolder))

{

Directory.CreateDirectory(publicKeyfolder);

}

if (!Directory.Exists(privateKeyfolder))

{

Directory.CreateDirectory(privateKeyfolder);

}

var publicKey = rsa.ToXmlString(false);

File.WriteAllText(publicKeyPath, publicKey);

File.WriteAllText(privateKeyPath, rsa.ToXmlString(true));

}

}

public byte[] EncryptData(string publicKeyPath, byte[] data)

{

byte[] cipherbytes;

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false;

rsa.FromXmlString(File.ReadAllText(publicKeyPath));

cipherbytes = rsa.Encrypt(data, false);

}

return cipherbytes;

}

public byte[] DecryptData(string privateKeyPath, byte[] data)

{

byte[] plain;

using (var rsa = new RSACryptoServiceProvider(2048))

{

rsa.PersistKeyInCsp = false

rsa.FromXmlString(File.ReadAllText(privateKeyPath));

plain = rsa.Decrypt(data, false);

}

return plain;

}

}

The first method is again AssignNewKey(). This method will generate both a public and a private key and store them in two XML files, c:temppublicKey.xml and c:tempprivateKey.xml. These two files represent the raw key data expressed as byte arrays.

The second method is the EncryptData method. This method takes a byte array containing the data you wish to encrypt. Then, the RSACryptoServiceProvider object is created and the size of the key is passed in. In this case, we are using a 2,048-bit key which is the recommended minimum key length to use currently.

Once this object has been created, the PersistKeyInCsp flag is set to false. This flag is set to true when you want to persist your key in a key container. The PersistKeyInCsp property is automatically set to true when you specify a key container name in a CspParameters object and use it to initialize an RSACryptoServiceProvider object. You can also specify a container name by using the KeyContainerName field. If you set the PersistKeyInCsp property to true without initializing the RSACryptoServiceProvider object with a CspParameters object, a random key container name prepended with “CLR” is created. In this example, we are not using a key container.

Next, the public key is imported into the RSACryptoServiceProvider instance. Then, all you need to do to encrypt some data is pass in your raw byte array of data. The second parameter is a Boolean to specify OAEP padding.

Check Also

digital signature

Digital Signature

An essential purpose of cryptography would be  to ensure nonrepudiation of a delivered message. This …

Leave a Reply

Your email address will not be published. Required fields are marked *