Please consider this code:
ServiceProvider services;
private void InitializeKeys()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDbContext<MyContext>();
serviceCollection.AddDataProtection().SetDefaultKeyLifetime(TimeSpan.FromDays(14)).PersistKeysToDbContext<MyContext>();
services = serviceCollection.BuildServiceProvider();
services.GetDataProtector("MyClass.v1").Protect("payload");
}
and MyContext
:
public class MyContext : DbContext, IDataProtectionKeyContext
{
public MyContext()
{
}
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; } = null!;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Server=.;Database=ThisIsMyDB;Trusted_Connection=True;TrustServerCertificate=True");
}
}
after I run my project one key was built successfully in database:
and protection was did successfully:
Code for protection:
var Provider = DataProtectionProvider.Create("MyClass.v1");
IDataProtector _protector = Provider.CreateProtector("MyClass.v1");
txtEncryptResult.Text = _protector.Protect(txtEncryptValue.Text);
This is when the case becomes interesting that I stopped the running application and I deleted all keys from database.
Now I want to decrypt protected value that I got from previous step and it still works:
Code for unprotect:
var Provider = DataProtectionProvider.Create("MyClass.v1");
IDataProtector _protector = Provider.CreateProtector("MyClass.v1");
txtDecryptResult.Text = _protector.Unprotect(txtDecryptValue.Text);
Why does it work whereas all keys were deleted??
Thanks
Edit 1)
Based on @Dai answer, I updated my codes and it works well:
var Provider = services.GetDataProtector("MyClass.v1");
IDataProtector _protector = Provider.CreateProtector("MyClass.v1");
txtEncryptResult.Text = _protector.Protect(txtEncryptValue.Text);
The problem is here:
Your code is using the
static class DataProtectionProvider
, which is just a utility class with factory methods for getting a quick-and-dirtyIDataProtectionProvider
instance without using (or participating in) a DI container - so theDataProtectionProvider.Create
method will not use yourServiceCollection
fromInitializeKeys
at all....and this is mentioned in the documentation for
DataProtectionProvider
:As per the documentation, the various
DataProtectionProvider.Create
overloads will return anIDataProtectionProvider
that uses a (unspecified) local filesystem location to store the keys: (emphasis mine)If you want to always get an
IDataProtectionProvider
that always uses the same configuration/options as set in yourInitializeKeys
method then you'll need to ensure you only ever callservices.GetDataProtector("MyClass.v1")
and never call the staticDataProtectionProvider.Create
methods.When I run it in Linqpad on my computer,
DataProtectionProvider.Create(String)
returns aMicrosoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector
which usesMicrosoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager
which saves keys toC:\Users\$me\AppData\Local\ASP.NET\DataProtection-Keys
- but this behaviour is machine-specific (the internalDefaultKeyStorageDirectories.GetKeyStorageDirectoryImpl()
method will return different directories based on your computer's OS and certain environment variables) - so you shouldn't depend on any assumptions you make about it.Remember that this library is still meant for use only with ASP.NET Core - I'm honestly surprised it works at all in a desktop program.