The ASP.NET Core Data Protection API (DPAPI) is an essential service in ASP.NET Core that is often overlooked. This post will give an overview of what it does and how we can persist the encryption keys in Azure Key Vault.
The API’s main purpose is to encrypt and decrypt data. For example, it is used to:
- Protect the various cookies issued by ASP.NET Core.
I blogged about how the cookies are protected in the Exploring what is inside the ASP.NET Core cookies blog post. - Protecting the OpenID Connect state and nonce parameters.
You can read about these two parameters in my blog post here.
The API is primarily designed to encrypt and secure short-lived data (from minutes to months), but it can also be used to encrypt data for long-term storage if needed.
How can you use the Data Protection API to protect your own data?
The API is typically used in ASP.NET Core applications, but nothing prevents you from using it in, for example, a console application. Just add the Microsoft.AspNetCore.DataProtection.Extensions NuGet package, and then you can start using it right away.
Here is a sample console application using the Data Protection API to protect and unprotect a string:
// Initialize the Data Protection system and store the keys c:\temp\keys
var provider = DataProtectionProvider.Create(new DirectoryInfo(@"c:\temp\keys"));
// Create a data protector
var protector = provider.CreateProtector("MyAppName");
string encryptedData = protector.Protect("Hello DPAPI");
string decryptedData = protector.Unprotect(encryptedData);
Console.WriteLine(encryptedData);
//CfDJ8PEJDb99-ddAhkM_GeKgmn1fcrWF9LGi10rTkU1f7IbW2y282ISIXZTgBBy_cL9iQ2RzxCyKbLlku7PlWVcTJw11NylWVCDqkdpjmsbm9U1chfg-rYUeBNFGwB-Q5q9b1w
Console.WriteLine(decryptedData); //Hello DPAPI
Interestingly, the API only works with strings, making it very easy to use. If you need to protect binary data, you can base64 encode it before you protect it.
How to use the Data Protection API in ASP.NET Core?
Using it in ASP.NET Core is also straightforward, as the Data Protection API is typically included by default in most ASP.NET Core projects. To use it in a controller, you can ask the Dependency Injection container for an instance of IDataProtectionProvider. Like this:
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger logger,
IDataProtectionProvider protectionProvider)
{
_logger = logger;
// Create a data protector
var protector = protectionProvider.CreateProtector("MyAppName");
var encryptedData = protector.Protect("Hello DPAPI");
var decryptedData = protector.Unprotect(encryptedData);
Console.WriteLine(encryptedData);
//CfDJ8Dsx1cA547pJnoAz-iXx9XYVi8GMYBHcEU9ceuB4Ep75Yr1I4pX4Rw3DWIE4H4cigg_-NvixoAoR5vl641cT-FEagETLBRoecfX011zsX7aPqf4OjxGNpCh-Bk6qfxgphw
Console.WriteLine(decryptedData); //Hello DPAPI
}
...
}
The Data Protection Key Ring
To protect the data, DPAPI uses an encryption key; if no key is found, it will automatically create one for us. DPAPI will introduce new keys regularly (default once every 90 days), meaning many keys will be involved over time. All these keys are stored in a key ring, and this key ring contains both the active key and the past keys.
You need to keep the old keys around if you want to be able to decrypt already encrypted data.
Persisting the Data Protection key King
The key ring should be persisted somewhere outside of your application, and there are many ready-made options to choose from, many are provided by Microsoft and the community.
However, one missing option is Azure Key Vault. In this post, we’ll write a sample provider for Azure Key Vault to showcase how simple it is to implement.
Why store the Data Protection Key Ring in Azure Key Vault?
Most services typically require some or all of the following items to operate: HTTPS/TLS certificates, the Data Protection Key Ring (DPAPI), encryption and signing keys, as well as secrets and configuration settings:
Azure Key Vault can securely store all of these items, helping to streamline your infrastructure and simplify key management.
It can even create some items for you; for example, if you use services like IdentityServer, it can generate token signing keys. This post will focus on persisting the key ring in Azure Key Vault.
Encrypting the keys in the key ring
Optionally, the keys inside the key ring can be encrypted at rest (when stored), and there is already support for that provided by using the Azure.Extensions.AspNetCore.DataProtection.Keys Nuget package from Microsoft. However, storing the key ring and the encryption key in the same location might be overkill.
The ASP.NET Core Data Protection API and security
Don’t forget to always ensure that you use separate key rings for your different environments so that if one of the key rings is compromised, it can’t be used against the other environments.
What does a key in the Data Protection key ring look like?
The key ring is by default represented as an XML document, and here’s a sample unencrypted key when it is stored in Azure Key Vault:
2024-02-12T15:47:21.2522781Z
2024-02-12T15:47:19.8787424Z
2024-05-12T15:47:19.8787424Z
xtlj8GlTE2t4OeoabEBG7Ry8XVXYzaTvxsM4UPs8kQYlepNM2/6FsmxRVE+BavFKj3ULwAiuqKmyC47QmCPLYw==
You can see above that the key is not encrypted at rest.
An example of a key ring where the keys are encrypted using a separate key in Azure Key Vault can look like this:
2024-02-13T08:30:51.9976822Z
2024-02-13T08:30:50.8851358Z
2024-05-13T08:30:50.8851358Z
https://dpapikeyvault.vault.azure.net/keys/MyDPAPIKey/c07cda675a3446f6a752a1e50c17c0c7
ZSWcsd302ouGxLFtx26MeuioxCRFhcwKxNTK7qL6TrG0d7GoiHV2B/Xtjr9CKNPgwkIUXv/mhTb/+lvwL15i/hh4kyYAPD/OftQjaHy3RRvHSTtkWZiCivyQr6PD8LbbZ4Wkznayzla60Ulwi+1TGhmUaGMTvpSo1mERVCK8iUEU7l8k1BCvJbEGn721nYvdBZQlBraPYNLaRDxQ3JCi6Brl4UImQwetByip2YPDWcKOMVMTH+JliVGrdZclLHk97E5MCIq1G4l+C5urQ6c8C1h+vJYQJ+5581eubGLXbC5pATa5bY8xCGObVj/6mZ5k9poOo+iKOU2OzL0N1h/leA==
M/Jh3zr94JYs2BYikdmJiA==
3lR+foXTx4awY5KbSNzZLGXfxtu0M9vaN0gc7XBDUwwbtcDloQyuHLI9T7l/FDmtdi/KO9pas1V5VBq/yVSdufmu6JnQmVIA8oHDodBD+T7+h5pM9zfP6Z6n7LcMuAxFv4T9PUEZIpThVB2dlC3pW5RNEWuFYP6oMPbk5RZw8V6dSydpBr6GWZXLUuFB3oAJB7+R/VCPtZypdYElZPVywdoEnLYarsoMuloqYAFz+3oP/y1XmHOZx5z1uYBw5B/3r851mYm9r7B5qU5LEV2Jq5CDMUbHgZAmca1cxuM5LKrBim74hYY03vtYulfxvae76aI2qNs91LmUfQTZklMskY+WA3AbEt0aUCo49n5mA+Ywffh1vpukoYRiC+7F1uC82Fea1GO0mHeGYzhHC517xbgQSON0PS3QxpOqkr8b7f8=
Does Azure Key Vault Have Limitations?
Yes, Azure Key Vault has some limitations around storing the key ring as a secret. The two main things to keep in mind are:
- We should store the key ring as one big secret in AKV, not the keys individually. This is to avoid making too many requests to AKV.
- There is an upper size limitation of around 25KB for a secret, meaning that there is an upper limit on the number of keys to keep in the key ring. My calculation estimates that this gives us enough space to hold about 12-13 keys, which should be sufficient for the most common use cases. This might, however, be a problem if you want to persist all the keys long-term and rotate them or revoke them regularly. Applying compression could increase this number.
Implementing the Azure Key Vault store
///
/// The basic interface for storing and retrieving XML elements.
///
public interface IXmlRepository
{
///
/// Gets all top-level XML elements in the repository.
///
IReadOnlyCollection GetAllElements();
///
/// Adds a top-level XML element to the repository.
///
/// The element to add.
void StoreElement(XElement element, string friendlyName);
}
Conclusions
Using Azure Key Vault to store the key ring is possible and implementing the persitence layer to support this is straight foward.
Feedback, comments, found any bugs?
About the author
Hi, I’m Tore! I have been fascinated by computers since I unpacked my first Commodore VIC-20. Today, I enjoy providing freelance development and developer training services, focusing on ASP.NET Core, IdentityServer, OpenID Connect, Architecture, and Web Security. You can connect with me on LinkedIn and Twitter, and you can find out more about me and my services here, as well as my courses for developers, including my course, Introduction to IdentityServer and OpenID-Connect.
Related posts by me:
Tore’s Newsletter
Be the First to Know! Get notified about my latest blog posts, upcoming presentations, webinars, and more — subscribe today!