I am using Microsoft.AspNetCore.DataProtection.IDataProtector to protect and unprotect strings stored in a SQL Server database. The key ring is persisted in the same SQL Server database and they are protected using a Self-signed X509Certificate2.
This is how the data protection configuration looks like:
// Configuring database context
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("MySites")));
// Adding Data Protection and configure persistence with Entity Framework
services.AddDataProtection()
.SetApplicationName("MySites.v1")
.PersistKeysToDbContext<ApplicationDbContext>()
.ProtectKeysWithCertificate(new X509Certificate2("certificate.pfx", "*****", X509KeyStorageFlags.MachineKeySet));
And this is how I unprotect data:
_dataProtector = dataProtectionProvider.CreateProtector("MySites.v1");
_dataProtector.Unprotect(protectedString)
I understand this method is not recommended to protect/unprotect long persisted data, but I also understand that nothing prevents us from doing so. I also understand that the keys are eventually rotated and you can only use the active key for protecting data, but you can keep using expired keys to unprotect data.
The Certificate protecting the keys is about to expire, and I am not sure how this will affect the ability to keep protecting and unprotecting data. So, I tried creating an API to backup the data just in case, but when I ran the application in my computer (debugging) but connected to the deployed data base (where the keys are persisted), I get the following error:
Message: The payload was invalid
StackTrace: at Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(Byte* pbCiphertext, UInt32 cbCiphertext, Byte* pbAdditionalAuthenticatedData, UInt32 cbAdditionalAuthenticatedData) at Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment1 ciphertext, ArraySegment
1 additionalAuthenticatedData) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.DataProtection.DataProtectionCommonExtensions.Unprotect(IDataProtector protector, String protectedData)\r\n at MySites.Controllers.SitesController.GetAll(Int32 siteCategoryId)
I also tried to use DangerousUnprotect but I got the same error
IPersistedDataProtector persistedProtector = _dataProtector as IPersistedDataProtector;
bool requiresMigration, wasRevoked;
var unprotectedPayload = persistedProtector.DangerousUnprotect(
protectedData: WebEncoders.Base64UrlDecode(site.PasswordHash),
ignoreRevocationErrors: true,
requiresMigration: out requiresMigration,
wasRevoked: out wasRevoked);
site.Password = WebEncoders.Base64UrlEncode(unprotectedPayload);
The deployed application works normally, and it is able to protect and unprotect data with no problem.