Encryption based on machine key cannot be used in Azure Web Apps


Description

The following message might appear in the logs after Shops App Service has been restarted:

System.Security.Cryptography.CryptographicException: Key not valid for use in specified state.

   at Microsoft.AspNetCore.DataProtection.Cng.DpapiSecretSerializerHelper.UnprotectWithDpapiCore(Byte* pbProtectedData, UInt32 cbProtectedData, Byte* pbOptionalEntropy, UInt32 cbOptionalEntropy)
   at Microsoft.AspNetCore.DataProtection.Cng.DpapiSecretSerializerHelper.UnprotectWithDpapi(Byte[] protectedSecret)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor.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 System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey key)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptor()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver.CanCreateAuthenticatedEncryptor(IKey key)

The issue occurs when keys are encrypted using one machine key and decrypted with another machine key.

Solution

To prevent CryptographicException from reoccurring, switch the key encryption from Machine to DPAPI-CERT:

  1. Put a trusted certificate into each Azure Web App that has to share the same encryption keys.
  2. Make sure Azure Web Apps load the certificates.
  3. Set the value of the EncryptionProtectionType application setting to DPAPI-CERT in the config.json file of each Commerce Engine role.
  4. Set the value of the EncryptionCertificateHash application setting to the thumbprint of your certificate in the config.json file of each Commerce Engine role.
  5. In the config.json file of each Commerce Engine role, set the value of the EncryptionKeyStorageLocation application setting to the location accessible to every Azure Web App that has the certificate installed.
  6. Restart the Commerce Engine App Services in the Web App.