0% found this document useful (0 votes)
65 views

Part - 4 Asymmetric Encryption in ASP - NET Core Web API

Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
65 views

Part - 4 Asymmetric Encryption in ASP - NET Core Web API

Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

Asymmetric Encryption in ASP.

NET Core Web API


Asymmetric Encryption, also known as public-key cryptography, is a type of encryption where two
different keys are used: a public key and a private key. The public key is used to encrypt data, while
the private key is used to decrypt data. This method ensures that even if the public key is known by
others, only the intended recipient with the private key can decrypt the message.

The primary advantage of Asymmetric Encryption is that it eliminates the need to share a secret key
between the sender and receiver, thus reducing the risk of key compromise.

What are the Different Components of Asymmetric Encryption?


The following are the Different Components of Asymmetric Encryption Algorithm:
 Public Key: This key is shared openly and used to encrypt data. It is unique to the receiver
and can be distributed widely without compromising security.
 Private Key: This key is kept secret by the owner and used to decrypt data. It is unique to the
receiver and must be kept secure.
 Ciphertext: The encrypted data produced after applying the encryption algorithm to the
plaintext. It is unreadable without the private key.
 Plaintext: The original data or message before encryption. This is the readable form of data
that needs to be protected.
 Encryption Algorithm: The process used to transform plaintext into ciphertext using the
public key. Common algorithms include RSA, ECC (Elliptic Curve Cryptography), and DSA.
When someone wants to send a secure message, they use the recipient's public key to
encrypt the message. Once encrypted, only the recipient's private key can decrypt it.
 Decryption Algorithm: The process used to transform ciphertext back into plaintext using
the private key. This algorithm ensures that only the private key holder can read the original
message. The recipient uses their private key to decrypt the message, turning it back into
readable plaintext

How Does Asymmetric Encryption Work?


Asymmetric Encryption involves a pair of keys: a public key and a private key. Here is a step-by-step
explanation of how asymmetric encryption works:
 Key Generation: A cryptographic algorithm generates a pair of keys: a public key and a
private key. The public key is shared openly, while the private key is kept secure and private
by the owner.
 Encryption: When the user wants to send a secure message to the receiver, the user will use
the public key of the receiver to encrypt the message. The encryption algorithm takes the
plaintext (the original message) and the public key of the receiver as input and produces
ciphertext (the encrypted message) as output.
 Transmission: The encrypted message (ciphertext) is sent over an insecure channel, such
as the internet, to the intended receiver.
 Decryption: The receiver uses their private key to decrypt the ciphertext. The decryption
algorithm takes the ciphertext and the private key as input and produces the original plaintext
as output.

For a better understanding, please have a look at the following diagram:


What are the Different Techniques to Implement Asymmetric Encryption in ASP.NET
Core Web API?
When implementing Asymmetric Encryption in an ASP.NET Core Web API, we can use the following
techniques.
1. RSA (Rivest-Shamir-Adleman) Algorithm: RSA is one of the most widely used algorithms
for public-key encryption. It provides strong security by using a pair of keys (public and
private) for encryption and decryption.
2. ECDSA (Elliptic Curve Digital Signature Algorithm): ECDSA is an elliptic curve-based
variant of the Digital Signature Algorithm (DSA). It is used for creating digital signatures and
provides high security with shorter key lengths compared to RSA.
3. DSA (Digital Signature Algorithm): DSA is primarily used for digital signatures and not for
encrypting data. It is a Federal Information Processing Standard for digital signatures.

Example to Understand RSA Algorithm in ASP.NET Core Web API:


Let us understand how to implement Encryption and Decryption using RSA Algorithm to secure our
services. We will create two applications. One ASP.NET Core Web API application which expose the
endpoints. Another Console application which will consume the API Endpoints. But here, we need to
transfer the data (Both Request Body and Response Body) in ciphertext, i.e., in encrypted format
using RSA Algorithm.

Creating Server Application:


Implementing RSA encryption and decryption to protect API endpoints for CRUD operations involves
several steps, including the creation and management of keys, the setup of the ASP.NET Core Web
API, and the development of a .NET console application to consume the API.

First create a new ASP.NET Core Web API Project named RSAServerAPP. Then create a folder
named Models within the Project root directory.

Key Storage Class


This class will store the public and private keys based on the Client ID. So, create a class file named
KeyStorage.cs and then copy and paste the following code:
using System.Security.Cryptography;

namespace RSAServerAPP.Models
{
public class KeyStorage
{
// A private static dictionary to store the RSA keys for each client.
// The dictionary keys are client IDs (string), and the values are tuples containing both
public and private keys.
private static readonly Dictionary<string, (string PublicKey, string PrivateKey)> _keyStore
= new();

// Method to generate a new pair of RSA keys for a specified clientId.


public void GenerateKeys(string clientId)
{
// Create a new RSA object with a key size of 2048 bits (256 Bytes) for cryptographic
operations.
using (var rsa = RSA.Create(2048))
{
// Export the public key information and convert it to a base64 string for easier
storage and transmission.
var publicKey = Convert.ToBase64String(rsa.ExportSubjectPublicKeyInfo());

// Export the private key in PKCS#8 format and convert it to a base64 string.
var privateKey = Convert.ToBase64String(rsa.ExportPkcs8PrivateKey());

// Store the generated keys in the _keyStore dictionary with the provided clientId as
the key.
_keyStore[clientId] = (publicKey, privateKey);
}
}

// Method to retrieve the public key for a given clientId.


public string GetPublicKey(string clientId)
{
// Attempt to retrieve the keys for the specified clientId. If found, return the public key;
otherwise, return null.
return _keyStore.TryGetValue(clientId, out var keys) ? keys.PublicKey : null;
}

// Method to retrieve the private key for a given clientId.


public string GetPrivateKey(string clientId)
{
// Attempt to retrieve the keys for the specified clientId. If found, return the private key;
otherwise, return null.
return _keyStore.TryGetValue(clientId, out var keys) ? keys.PrivateKey : null;
}
}
}
Objectives of Methods
 GenerateKeys: The primary purpose of this method is to create a new pair of RSA public and
private keys for a specific client. This method ensures that each client has a unique set of
keys, which is essential for secure communications (e.g., encrypting and decrypting data).
 GetPublicKey: This method fetches the public key for a given client. The public key is used
to encrypt data that has been decrypted with the corresponding private key.
 GetPrivateKey: This method fetches the private key for a given client. The private key is
used to decrypt data that has been encrypted with the corresponding public key.

Define the Employee Model:


Next, create a simple Employee model. So, within the Models folder, create a class file named
Employee.cs and then copy and paste the following code:
namespace RSAServerAPP.Models
{
public class Employee
{
public int? Id { get; set; }
public string Name { get; set; }
public string Position { get; set; }
public decimal Salary { get; set; }
}
}

Create an RSA Encryption Service in ASP.NET Core Web API


Create a service to handle RSA encryption, and decryption. So, create a class file named
RSAEncryptionService.cs and then copy and paste the following code. The flowing class is used to
handle encryption and decryption of data using RSA keys. I've added comments to each line of the
code to explain its functionality:
using System.Security.Cryptography;
using System.Text;

namespace RSAServerAPP.Models
{
// The RSAEncryptionService class provides methods to encrypt and decrypt data using
RSA encryption.
public class RSAEncryptionService
{
// Encrypts a string using a public key.
public string Encrypt(string data, string publicKey)
{
// Creates a new RSA instance for cryptographic operations.
using (var rsa = RSA.Create())
{
// Imports the public key, provided in base64 format, to set up the RSA object for
encryption.
rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKey), out _);

// Converts the string data to a byte array in UTF-8 encoding.


var dataBytes = Encoding.UTF8.GetBytes(data);

// Encrypts the data bytes using the public key and OAEP padding with SHA-256.
var encryptedData = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);

// Converts the encrypted byte array back to a base64 string for easy storage or
transmission.
return Convert.ToBase64String(encryptedData);
}
}

// Decrypts a string using a private key.


public string Decrypt(string encryptedData, string privateKey)
{
// Creates a new RSA instance for cryptographic operations.
using (var rsa = RSA.Create())
{
// Imports the private key, provided in base64 format, to set up the RSA object for
decryption.
rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);

// Converts the base64 encoded encrypted data back into a byte array.
var dataBytes = Convert.FromBase64String(encryptedData);

// Decrypts the data bytes using the private key and OAEP padding with SHA-256.
var decryptedData = rsa.Decrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);

// Converts the decrypted byte array back to a UTF-8 encoded string.


return Encoding.UTF8.GetString(decryptedData);
}
}
}
}
Objectives of Methods
 Encrypt: Encrypts plain text data into a ciphertext using RSA public key encryption. This
method ensures that data can only be decrypted by the corresponding private key,
safeguarding sensitive information during transmission.
 Decrypt: Decrypts ciphertext back into plain text using an RSA private key. This method
ensures that only the intended recipient, who holds the private key, can read the data.

Create the Employee Controller


Create a controller to handle CRUD operations and protect them with RSA encryption. So, create an
API Empty Controller named EmployeesController within the Controllers folder and then copy and
paste the following code. The following controller handles CRUD operations for an employee
database with encryption and decryption using RSA keys. Below, I've added comments to each line of
the code to explain its functionality and purpose:
using Microsoft.AspNetCore.Mvc;
using RSAServerAPP.Models;
using System.Text.Json;

namespace RSAServerAPP.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EmployeesController : ControllerBase
{
// Static list simulating a database table storing employee records.
private static List<Employee> Employees = new List<Employee>
{
new Employee { Id = 1, Name = "Alice Smith", Position="DBA", Salary = 75000 },
new Employee { Id = 2, Name = "Bob Johnson", Position="HR", Salary = 60000 },
new Employee { Id = 3, Name = "Carol White", Position="Developer", Salary = 55000 }
};

// Services for RSA encryption and key storage.


private readonly RSAEncryptionService _encryptionService;
private readonly KeyStorage _keyStorage;

// Constructor initializes the RSA encryption and key storage services.


public EmployeesController()
{
_encryptionService = new RSAEncryptionService();
_keyStorage = new KeyStorage();
}

// HTTP GET endpoint to generate RSA keys for a client and return them.
[HttpGet("generate-keys")]
public IActionResult GenerateKeys([FromHeader] string clientId)
{
_keyStorage.GenerateKeys(clientId);
var publicKey = _keyStorage.GetPublicKey(clientId);
var privateKey = _keyStorage.GetPrivateKey(clientId);
return Ok(new { PublicKey = publicKey, PrivateKey = privateKey });
}

// HTTP POST endpoint to create a new employee from encrypted data.


[HttpPost("create")]
public IActionResult Create([FromHeader] string clientId, [FromBody] EncryptedRequest
request)
{
var privateKey = _keyStorage.GetPrivateKey(clientId);
var decryptedData = _encryptionService.Decrypt(request.Data, privateKey);
var employee = JsonSerializer.Deserialize<Employee>(decryptedData);
employee.Id = Employees.Count > 0 ? Employees.Max(e => e.Id) + 1 : 1;
Employees.Add(employee);
var encryptedResponse =
_encryptionService.Encrypt(JsonSerializer.Serialize(employee),
_keyStorage.GetPublicKey(clientId));
return Ok(new EncryptedDataResponse { Data = encryptedResponse });
}

// HTTP GET endpoint to retrieve an employee's details, encrypt the data before sending it
back.
[HttpGet("{id}")]
public IActionResult Get(int id, [FromHeader] string clientId)
{
var employee = Employees.FirstOrDefault(e => e.Id == id);
if (employee == null) return NotFound();

var data = JsonSerializer.Serialize(employee);


var encryptedData = _encryptionService.Encrypt(data,
_keyStorage.GetPublicKey(clientId));
return Ok(new EncryptedDataResponse { Data = encryptedData });
}

// HTTP PUT endpoint to update an existing employee's details from encrypted data.
[HttpPut("{id}")]
public IActionResult Update(int id, [FromHeader] string clientId, [FromBody]
EncryptedRequest request)
{
var privateKey = _keyStorage.GetPrivateKey(clientId);
var decryptedData = _encryptionService.Decrypt(request.Data, privateKey);
var updatedEmployee = JsonSerializer.Deserialize<Employee>(decryptedData);
var employee = Employees.FirstOrDefault(e => e.Id == id);
if (employee == null) return NotFound();

employee.Name = updatedEmployee.Name;
employee.Position = updatedEmployee.Position;
employee.Salary = updatedEmployee.Salary;
var encryptedResponse =
_encryptionService.Encrypt(JsonSerializer.Serialize(employee),
_keyStorage.GetPublicKey(clientId));
return Ok(new EncryptedDataResponse { Data = encryptedResponse });
}

// HTTP DELETE endpoint to remove an employee by ID.


[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var employee = Employees.FirstOrDefault(e => e.Id == id);
if (employee == null) return NotFound();

Employees.Remove(employee);
return Ok();
}
}

// Class to handle encrypted request data.


public class EncryptedRequest
{
public string Data { get; set; }
}

// Class to handle encrypted data responses.


public class EncryptedDataResponse
{
public string Data { get; set; }
}
}

RSAClientAPP
Next, we need to create the Client APP consuming the service with RSA encryption and decryption.
For this, we are going to create a Console Application. So, create a Dot Net Console Application
named RSAClientAPP. Once you create the Console Application, modify the Program class code as
follows:
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

namespace RSAClientAPP
{
public class Program
{
// HttpClient instance for sending requests to a server.
private static readonly HttpClient client = new HttpClient();

// The entry point of the program.


public static async Task Main(string[] args)
{
// Identifier for the client.
var clientId = "Client1";

// Add clientId to the default request headers of HttpClient.


client.DefaultRequestHeaders.Add("clientId", clientId);

// Request to generate RSA keys from the server and retrieve them.
var keysResponse = await
client.GetFromJsonAsync<KeysResponse>("https://localhost:7102/api/Employees/generate-
keys");
var publicKey = keysResponse.PublicKey;
var privateKey = keysResponse.PrivateKey;

// Create a new employee object.


var newEmployee = new Employee
{
Name = "John Doe",
Position = "Developer",
Salary = 60000
};

// Encrypt the new employee data using the public key and send to the server.
var encryptedData = EncryptData(newEmployee, publicKey);
var createRequest = new EncryptedRequest { Data = encryptedData };

// Send the encrypted employee data to the server to create a new employee.
var createResponse = await
client.PostAsJsonAsync("https://localhost:7102/api/Employees/create", createRequest);
var createdEmployeeData = await
createResponse.Content.ReadFromJsonAsync<EncryptedDataResponse>();
var createdEmployeeJson = DecryptData(createdEmployeeData.Data, privateKey);
var createdEmployee = JsonSerializer.Deserialize<Employee>(createdEmployeeJson);
Console.WriteLine($"Created Employee: {JsonSerializer.Serialize(createdEmployee)}");

// Retrieve the created employee's data from the server and decrypt it.
var getResponse = await
client.GetAsync($"https://localhost:7102/api/Employees/{createdEmployee.Id}");
var encryptedEmployee = await
getResponse.Content.ReadFromJsonAsync<EncryptedDataResponse>();
var decryptedEmployeeJson = DecryptData(encryptedEmployee.Data, privateKey);
var decryptedEmployee =
JsonSerializer.Deserialize<Employee>(decryptedEmployeeJson);
Console.WriteLine($"Retrieved Employee:
{JsonSerializer.Serialize(decryptedEmployee)}");

// Update the employee's name, encrypt the updated data, and send it to the server.
createdEmployee.Name = "Jane Doe";
encryptedData = EncryptData(createdEmployee, publicKey);
var updateRequest = new EncryptedRequest { Data = encryptedData };
var updateResponse = await
client.PutAsJsonAsync($"https://localhost:7102/api/Employees/{createdEmployee.Id}",
updateRequest);
var updatedEmployeeData = await
updateResponse.Content.ReadFromJsonAsync<EncryptedDataResponse>();
var updatedEmployeeJson = DecryptData(updatedEmployeeData.Data, privateKey);
var updatedEmployee = JsonSerializer.Deserialize<Employee>(updatedEmployeeJson);
Console.WriteLine($"Updated Employee:
{JsonSerializer.Serialize(updatedEmployee)}");

// Send a request to delete the employee from the server.


var deleteResponse = await
client.DeleteAsync($"https://localhost:7102/api/Employees/{createdEmployee.Id}");
if (deleteResponse.IsSuccessStatusCode)
{
Console.WriteLine("Employee deleted successfully.");
}

// Pause the console until a key is pressed.


Console.ReadKey();
}

// Encrypts data using an RSA public key.


private static string EncryptData(object data, string publicKey)
{
using (var rsa = RSA.Create())
{
rsa.ImportSubjectPublicKeyInfo(Convert.FromBase64String(publicKey), out _);
var dataBytes = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(data));
var encryptedData = rsa.Encrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);
return Convert.ToBase64String(encryptedData);
}
}

// Decrypts data using an RSA private key.


private static string DecryptData(string encryptedData, string privateKey)
{
using (var rsa = RSA.Create())
{
rsa.ImportPkcs8PrivateKey(Convert.FromBase64String(privateKey), out _);
var dataBytes = Convert.FromBase64String(encryptedData);
var decryptedData = rsa.Decrypt(dataBytes, RSAEncryptionPadding.OaepSHA256);
return Encoding.UTF8.GetString(decryptedData);
}
}
}

// Definition of the Employee model.


public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public string Position { get; set; }
public decimal Salary { get; set; }
}

// Response model for receiving keys.


public class KeysResponse
{
public string PublicKey { get; set; }
public string PrivateKey { get; set; }
}

// Model for encrypted requests.


public class EncryptedRequest
{
public string Data { get; set; }
}

// Model for encrypted data responses.


public class EncryptedDataResponse
{
public string Data { get; set; }
}
}

Testing the Application:


First, run the ASP.NET Core Web API Application, then run the Console Application and you should
get the output as expected as shown in the below image:

Differences Between Asymmetric and Symmetric Encryption


Asymmetric and symmetric encryption are two primary cryptographic methods used to secure data.
The following are the key differences between them:

Key Usage:
 Symmetric Encryption: Both the sender and receiver use the same secret key for encryption
and decryption. This requires that the key must be securely exchanged and kept confidential.
 Asymmetric Encryption: Involves two keys: a public key for encryption and a private key for
decryption. The public key can be freely distributed, while the private key is kept secure by
the owner.

Key Management:
 Symmetric Encryption: Requires secure key distribution mechanisms, as the same key
must be shared between communicating parties. This can be challenging in large-scale
environments.
 Asymmetric Encryption: Simplifies key distribution since the public key can be shared
openly without compromising security. Only the private key must be protected.

Speed:
 Symmetric Encryption: Generally, much faster than asymmetric encryption due to the
simplicity of the algorithms used. It is well-suited for encrypting large amounts of data.
 Asymmetric Encryption: Slower because of the complexity of the algorithms. Typically used
for encrypting small amounts of data, such as keys or digital signatures.

Security:
 Symmetric Encryption: Security depends on the strength of the encryption algorithm and
the secrecy of the key. If the key is compromised, the security is breached.
 Asymmetric Encryption: Offers higher security due to the use of two keys. Even if the public
key is known, without the private key, it is computationally infeasible to decrypt the data.

Examples of Algorithms:
 Symmetric Encryption: Common algorithms include AES (Advanced Encryption Standard),
DES (Data Encryption Standard), and 3DES (Triple DES).
 Asymmetric Encryption: Common algorithms include RSA (Rivest-Shamir-Adleman), ECC
(Elliptic Curve Cryptography), and DSA (Digital Signature Algorithm).

You might also like