When it comes to protect data, one direct way is to encrypt it by adopting certain cryptographic algorithm. In .NET, there are many encryption or decryption algorithms available to use. Like storing secrets in a container with a key, you don't want to expose that key to anyone else if you want to keep the secrets. In .NET Core or f.NET 5/6, data protection system provides quite a few approaches to secure the private key.
Different ways to secure the keys
On Azure, we can store the keys in Azure Key Vault; in other applications, we can persist the key to a disk that cannot be accessed by others. You can also upload the keys to a database via EntityFramework via DbContext so that only users who have access to the database can access the private key and use it to encrypt or decrypt messages.
The following is one example:
services.AddDataProtection() .PersistKeysToDbContext<ApplicationDbContext>() .SetDefaultKeyLifetime(TimeSpan.FromDays(180));
The payload was invalid error
Exceptions can be thrown out using the above code snippet:
System.Security.Cryptography.CryptographicException: The payload was invalid. at Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(Byte* pbCiphertext, UInt32 cbCiphertext, Byte* pbAdditionalAuthenticatedData, UInt32 cbAdditionalAuthenticatedData) at Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment`1 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)
There are usually two typical causes for the above exception:
- Private key is not persisted thus if the value was encrypted with a key from one instance, it cannot be decrypted using the current key.
- Application name is not set.
Since we are persisting the keys to a database, the latter is the root cause.
Fix the problem
To fix the problem, we just need to call SetApplicationName function to ensure the application name is not consistent among different runs. If it is not specified, a random application name will be used and even if the key is the same the payload cannot be decrypted.
services.AddDataProtection() .PersistKeysToDbContext<ApplicationDbContext>() .SetApplicationName("YourAppName") .SetDefaultKeyLifetime(TimeSpan.FromDays(180));