-
Notifications
You must be signed in to change notification settings - Fork 88
CryptographicException results when attempting to protect data after configuring with ProtectKeysWithCertificate #139
Description
We have an Asp.NET MVC 5 app targeting DNX 4.5.1, and whenever we attempt to use the ProtectKeysWithCertificate
method to configure the keys to be encrypted to a specified X509 certificate before being persisted to storage, we get a CryptographicException
, with the message: Unable to retrieve the decryption key.
This is how data protection is being configured for the time being in our Startup
class. (Code that I presume is irrelevant has been removed for brevity.)
string _contentRootPath;
public Startup(IHostingEnvironment hostingEnvironment)
{
_contentRootPath = hostingEnvironment.ContentRootPath;
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
var pfxFileInfo = new DirectoryInfo(_contentRootPath).EnumerateFiles("*.pfx").Single();
var x509Cert = new X509Certificate2(File.ReadAllBytes(pfxFileInfo.FullName), "supersecretpassword");
services.AddDataProtection()
.SetApplicationName("hrselfservice")
.ProtectKeysWithCertificate(x509Cert)
.PersistKeysToFileSystem(new DirectoryInfo(_contentRootPath));
}
For the purposes of testing, a self-signed pfx
file exists at the location corresponding to the ContentRootPath
defined above.
The following controller effectively allows me to reproduce the exception we are getting:
public class DataProtectionController : Controller
{
private readonly IDataProtector _dataProtector;
public DataProtectionController(IDataProtectionProvider dataProtectionProvider)
{
_dataProtector = dataProtectionProvider.CreateProtector("TestDataProtection");
}
[HttpGet]
public bool TestDataProtection()
{
var originalData = "This is only a test";
var protectedData = _dataProtector.Protect(originalData);
var unprotectedData = _dataProtector.Unprotect(protectedData);
return unprotectedData == originalData;
}
}
When the Protect
method (above) is called, a new "key" file (e.g. key-4c76c163-3842-42ae-a502-d1c92e9f5aa0.xml
) is created (with encrypted data) alongside the .pfx
file, and then the following exception is thrown, presumably while it's trying to use data from the newly created key file:
System.Security.Cryptography.CryptographicException: Unable to retrieve the decryption key.
at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
at Microsoft.AspNetCore.DataProtection.KeyManagement.DeferredKey.<>c__DisplayClass1_0.<GetLazyEncryptorDelegate>b__0()
at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Lazy`1.get_Value()
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptorInstance()
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRing.KeyHolder.GetEncryptorInstance(Boolean& isRevoked)
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRing.get_DefaultAuthenticatedEncryptor()
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext)
at Microsoft.AspNetCore.DataProtection.DataProtectionExtensions.Protect(IDataProtector protector, String plaintext)
According to the documentation, I believe we're using the API correctly, but perhaps we're missing something about how the X509 certificate is supposed to be set up for decryption of key data. Can you help confirm that we're using the API correctly?
It's worth noting that if we comment out the .ProtectKeysWithCertificate(x509Cert)
line in the above example, the key file is created (without the encrypted key value, of course), and the Protect
and Unprotect
methods of IDataProtector
work without throwing any exceptions.
And BTW, we're using version "1.0.0-rc2-20254" of Microsoft.AspNetCore.DataProtection
.