Encryption transforms data into a form that can be read only by someone who has a key that allows them to decrypt it. You can use encryption to protect data “at rest” (data that resides in a data store) or to protect data “in motion” (data that is being sent over a network).
This article will examine how we can work with two types of encryption in C#, symmetric encryption and asymmetric encryption. Symmetric encryption uses one key for both encryption and decryption. Asymmetric encryption uses two distinct keys for encryption and decryption.
To work with the code examples provided in this article, you should have Visual Studio 2022 installed in your system. If you don’t already have a copy, you can download a copy from here.
Create a .NET Core console application project in Visual Studio
First off, let’s create a .NET Core console application project in Visual Studio 2022. Assuming Visual Studio 2022 is installed in your system, follow the steps outlined below to create a new .NET Core console application project.
- Launch the Visual Studio 2022 Preview IDE.
- Click on “Create new project.”
- In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
- Click Next.
- In the “Configure your new project” window shown next, specify the name and location for the new project.
- Click Next.
- In the “Additional information” window, specify .NET 7 as the .NET version you would like to use.
- Click Create.
This will create a new .NET 7 console application project in Visual Studio 2022. We’ll use this project to work with encryption in the subsequent sections of this article.
Symmetric encryption vs. asymmetric encryption
Encryption is of two types: symmetric encryption and asymmetric encryption. Both symmetric and asymmetric encryption can help protect sensitive data residing in your data store or in transit. C# provides built-in support for symmetric and asymmetric encryption through the System.Security.Cryptography namespace.
Whereas symmetric encryption uses only one key for encrypting and decrypting data, asymmetric encryption uses two keys: a public key used for encrypting the data and a private key used for decrypting the data. Symmetric encryption is generally faster and more efficient, but you must keep the key secret, because anyone with access to the key can decrypt the data. Asymmetric encryption is slower than symmetric encryption, but it’s also much more secure because the decryption key is not shared. Only the person possessing the private key will be able to decode the data.
The differences between symmetric and asymmetric encryption make them suitable for different use cases, as Microsoft points out here in the .NET documentation:
Symmetric encryption and asymmetric encryption are performed using different processes. Symmetric encryption is performed on streams and is therefore useful to encrypt large amounts of data. Asymmetric encryption is performed on a small number of bytes and is therefore useful only for small amounts of data.
This explains why symmetric encryption is often used to protect data sent over the network (such as an email) while asymmetric encryption is often used to protect sensitive data such as social security numbers, passwords, and credit card numbers.
In the following sections, we’ll encrypt and decrypt a string using C#, first with symmetric encryption and then with asymmetric encryption. We’ll use a string as the data in our examples to keep things simple.
Implementing symmetric encryption in C#
To implement symmetric encryption, you will need to generate a 256-bit key for encrypting and decrypting data. Symmetric encryption is faster than asymmetric encryption but less secure because you can use the same key for encrypting and decrypting data. The receiver uses the same shared secret to decrypt the message after receiving it from the sender. If the key is not shared securely, a third party could use it to decrypt and read the data.
In the console application project you created earlier, create a static C# class named SymmetricEncryptionDecryptionManager in a file named SymmetricEncryptionDecryptionManager.cs and enter the following code.
using System.Security.Cryptography;
using System.Text;
namespace EncryptionDemo
{
public class SymmetricEncryptionDecryptionManager
{
public static string Encrypt(string data, string key)
{
byte[] initializationVector = Encoding.ASCII.GetBytes("abcede0123456789");
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = initializationVector;
var symmetricEncryptor = aes.CreateEncryptor(aes.Key, aes.IV);
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream as Stream,
symmetricEncryptor, CryptoStreamMode.Write))
{
using (var streamWriter = new StreamWriter(cryptoStream as Stream))
{
streamWriter.Write(data);
}
return Convert.ToBase64String(memoryStream.ToArray());
}
}
}
}
public static string Decrypt(string cipherText, string key)
{
byte[] initializationVector = Encoding.ASCII.GetBytes("abcede0123456789");
byte[] buffer = Convert.FromBase64String(cipherText);
using (Aes aes = Aes.Create())
{
aes.Key = Encoding.UTF8.GetBytes(key);
aes.IV = initializationVector;
var decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (var memoryStream = new MemoryStream(buffer))
{
using (var cryptoStream = new CryptoStream(memoryStream as Stream,
decryptor, CryptoStreamMode.Read))
{
using (var streamReader = new StreamReader(cryptoStream as Stream))
{
return streamReader.ReadToEnd();
}
}
}
}
}
}
}
In the preceding code listing, notice there are two methods, Encrypt and Decrypt. The Encrypt method accepts the data to encrypt and the secret key as parameters. It leverages the Advanced Encryption Standard (AES) algorithm to perform symmetric data encryption using the secret key. The encrypted data is returned in the form of a Base64 string.
The Decrypt method accepts the encrypted data and the secret key as parameters. It converts the cipher text to a byte array, which is used to decrypt the data using the secret key. The decrypted data is returned as a string.
You can use the following code snippet to encrypt and decrypt data using the Encrypt and Decrypt methods ofthe SymmetricEncryptionDecryptionManager class.
var encryptedText = SymmetricEncryptionDecryptionManager.Encrypt("This is sample text.", key);
Console.WriteLine(encryptedText);
var decryptedText = SymmetricEncryptionDecryptionManager.Decrypt(encryptedText, key);
Console.WriteLine(decryptedText);
Implementing asymmetric encryption in C#
In asymmetric encryption, two different keys are used to encrypt and decrypt data. The public key is used to encrypt, and the private key is used to decrypt. You must have both a public key and a private key to implement asymmetric encryption.
To encrypt data using asymmetric encryption, you first need to generate a public/private key pair. You can do this using the RSA algorithm as shown below.
var rsa = new RSACryptoServiceProvider();
string publicKeyXML = rsa.ToXmlString(false);
string privateKeyXML = rsa.ToXmlString(true);
Once you have generated the key pair, you can use the public key to encrypt data.
byte[] data = Encoding.UTF8.GetBytes("Hello world!");
byte[]encryptedData = rsa.Encrypt(data, false);
Then, to decrypt the data, you will need to use the private key.
byte[] decryptedData = rsa.Decrypt(encryptedData, false);
string message = Encoding.UTF8.GetString(decryptedData);
Let us create a new class named AsymmetricEncryptionDecryptionManager with the following code.
public class AsymmetricEncryptionDecryptionManager
{
public static string Encrypt(string data, RSAParameters rsaParameters)
{
using(var rsaCryptoServiceProvider = new RSACryptoServiceProvider())
{
rsaCryptoServiceProvider.ImportParameters(rsaParameters);
var byteData = Encoding.UTF8.GetBytes(data);
var encryptedData = rsaCryptoServiceProvider.Encrypt(byteData, false);
return Convert.ToBase64String(encryptedData);
}
}
public static string Decrypt(string cipherText, RSAParameters rsaParameters)
{
using(var rsaCryptoServiceProvider = new RSACryptoServiceProvider())
{
var cipherDataAsByte = Convert.FromBase64String(cipherText);
rsaCryptoServiceProvider.ImportParameters(rsaParameters);
var encryptedData = rsaCryptoServiceProvider.Decrypt(cipherDataAsByte, false);
return Encoding.UTF8.GetString(encryptedData);
}
}
}
You can use the following code snippet to encrypt and decrypt data using the Encrypt and Decrypt methods of the AsymmetricEncryptionDecryptionManager class.
var rsaCryptoServiceProvider = new RSACryptoServiceProvider(2048);
var cipherText = AsymmetricEncryptionDecryptionManager.Encrypt("This is sample text.", rsaCryptoServiceProvider.ExportParameters(false));
Console.WriteLine(cipherText);
var plainText = AsymmetricEncryptionDecryptionManager.Decrypt(cipherText, rsaCryptoServiceProvider.ExportParameters(true));
Console.WriteLine(plainText);
Figure 1 below shows the output when you execute the above program.
Note that you can merge both SymmetricEncryptionDecryptionManager and AsymmetricEncryptionDecryptionManager into one class and write overloaded methods for symmetric and asymmetric encryption and decryption. You can use this knowledge to build secure applications or websites that protect data from unauthorized access.