Encryption and Decryption in ASP.NET Core

5 (5 votes)

The ASP.NET Core framework provides a new API for protecting data, including mechanisms for encryption and decryption. This article takes a quick look at how they can be used.

Difference between Encoding, Encryption and Hashing

First, I want to quickly go over some basics so you can make the right choice, particularly when it comes to managing passwords securely. I have seen articles purportedly about encrypting passwords in ASP.NET that show how to Base-64 encode and decode a string. Encoding data is not a security measure - even if the resulting output is unreadable to humans. Encoding data simply provides protection against data corruption when transferring that data from one place to another, such as across networks.

Encryption is similar to encoding in that it is designed to be reversible. However, encryption uses a cryptographic algorithm to convert the data from one form to another, and only those with access to a particular cryptographic key are able to unscramble it back to its original form.

Finally, there is hashing, which shares a reliance on cryptography with encryption, but is a one-way process. Data that has been properly hashed cannot be unhashed or decoded. Hashing is typically recommended for secure storage of passwords, and is used by all the Identity/Membership frameworks in .NET. When a user registers with a web site, the password they provide is hashed and then the hashed value is stored in the database. When they attempt to log in subsequently, the password they provide is hashed, and the newly hashed value is compared to the one that has already been stored. Hashing is deterministic in that it always produces the same result, given the same input.

Data Protection APIs in ASP.NET Core

The data protection APIs provide mechanisms for encryption and hashing but this article is only concerned with encryption. Encryption requires a key, which is created and managed by the data protection system. Keys are created with a default lifetime of 90 days, and stored in a suitable location according to the environment. Keys are temporary, so the data protection API is designed mainly for short term data protection scenarios such as encryption of authentication cookies or query string data. It is not designed for the protection of data that, for example, might be stored long term in a database.

The data protection system is enabled as part of the default services for an ASP.NET Core application, so you do not need to do anything in your StartUp method unless you want to reconfigure the default key storage location or the life time of keys. If that is the case, you can use the ConfigureDataProtection extension method in the ConfigureServices method:

public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureDataProtection(dp =>
    {
        dp.PersistKeysToFileSystem(new DirectoryInfo(@"c:\keys"));
        dp.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
    });
    ....

The data protection system is built upon two core concepts - a data protection provider (represented by the IDataProtectionProvider interface), which is used to create a data protector (represented by the IDataProtector interface). The data protector is used to encrypt and decrypt data. Because the data protection system has been added to the application's services collection by default, it can be made available via dependency injection. Here's how you can inject the IDataProtectionProvider into a controller and then use it to create an instance of an IDataProtector in the controller's constructor:

public class HomeController : Controller
{
    IDataProtector _protector;
        
    public HomeController(IDataProtectionProvider provider)
    {
        _protector = provider.CreateProtector(GetType().FullName);
    }

The CreateProtector method of the IDataProtectionProvider requires a string, known as a "purpose" string. This is used to differentiate one data protector from another in the same application. Data that has been protected by one data protector cannot be unprotected by a different protector. The recommendation is that you pass in the fully qualified name of the current component as this won't conflict with protectors instantiated in other parts of the system.

Encrypting Query Strings/Route Data

One of the most frequent encryption scenarios that I see questions about is in the realm of encrypting identity values in query strings or route data to prevent tampering, and potential access to restricted data. The following section of code illustrates getting some data from a service, and then transforming that data to a view model while encrypting the ID of each item for use in a URL:

public IActionResult Index()
{
    var model = _service.GetAll().Select(c => new ContractViewModel {
        Id = _protector.Protect(c.Id.ToString()),
        Name = c.Name }).ToList();
    return View(model);
}

The Protect method takes a byte array or a string, and encrypts it. The encrypted value is then used in the view to form the Id parameter of a route:

@foreach(var entry in Model)
{
    <div><a asp-action="Details" asp-route-id="@entry.Id">@entry.Name</a></div>
}

Data Protection ASP.NET Core

The links point to an action named Details, where the IDataProtector's Unprotect method is used to decrypt the Id parameter and retrieve details of the selected item:

public IActionResult Details(string id)
{
    var contract = _service.Find(Convert.ToInt32(_protector.Unprotect(id)));
    return View(contract);
}

You can see the encrypted value in the URL when any of the links are clicked:

Data Protection ASP.NET Core

Summary

This article provides an introduction to the Data Protection system that has been built from the ground up for use with ASP.NET Core applications. It began with a refresher on the differences between encoding, encryption and hashing, and when you might want to use each process. Then it described the core concepts on which the encryption/decryption system is built and how to use the components to securely encrypt and decrypt data.

Even though it is still at RC 1 stage at the time of writing, the documentation for the Data Protection APIs is quite comprehensive, and is well worth a read at https://docs.asp.net/en/latest/security/data-protection/index.html.

Date Posted:
Last Updated:
Posted by:
Total Views to date: 5543

1 Comment

- Steve

A very informative, well-written article. Thank you very much.

Recent Comments

Jon 31/03/2016 21:36
In response to Exploring Prefix: A Free ASP.NET Profiling Tool
We had the exact same experience, finding multiple bugs in an application that we thought was pretty...

ranjith 31/03/2016 05:50
In response to A Better Way To Export Gridviews To Excel
Hello Mike. i am exporting from gridview, because i have some images in my gridview. but i am error...

Matt Watson 30/03/2016 22:19
In response to Exploring Prefix: A Free ASP.NET Profiling Tool
Glad you are loving it! Matt from Stackify...

Dmitry 28/03/2016 04:26
In response to Solved - The Microsoft.ACE.OLEDB.12.0 provider is not registered on the local machine
thank you about the VS 32-bit remark...

federico 26/03/2016 11:29
In response to Request.Form Is Empty When Posting To ASPX Page
thanks!....

Micheal 23/03/2016 00:58
In response to ASP.NET MVC 5 with EF 6 - Working With Files
Thanks for the code. its pretty straightforward. worked for me on my first trial. Perfect!...

Francisco 22/03/2016 20:35
In response to ASP.NET MVC 5 with EF 6 - Working With Files
The post is very good, thanks...

Nick Brown 22/03/2016 13:53
In response to Adding A View
Hi, Many thanks for this tutorial, it's helping me get started with MVC. In VB (VS 2013) I get late...

ferry mae 22/03/2016 13:04
In response to Send form content by email in ASP.NET
do i need to change this? message.To.Add(new MailAddress("me@domain.com")); message.CC.Add(new you...

Keith 22/03/2016 12:02
In response to Creating a Connection String and Working with SQL Server LocalDB
As always worst explanation, but this time you rocked with plagiarism too .. huhh.. copied from Rick...