using System.Security.Cryptography; using IdentityShroud.Core.Contracts; using IdentityShroud.Core.Model; using IdentityShroud.Core.Security; namespace IdentityShroud.Core.Services; public class DataEncryptionService( IDekEncryptionService dekCryptor) : IDataEncryptionService { public EncryptedValue Encrypt(RealmDek dek, ReadOnlySpan plain) { Span key = stackalloc byte[dekCryptor.GetDecryptedSize(dek.KeyData)]; try { dekCryptor.Decrypt(dek.KeyData, key); byte[] cipher = Encryption.Encrypt(plain, key); return new (dek.Id, cipher); } finally { CryptographicOperations.ZeroMemory(key); } } public byte[] Decrypt(IReadOnlyList deks, EncryptedValue input) { // Note a missing key SHOULD not happen. If it does happen something has seriously gone wrong like // - Old key removed before migration completed (should not be possible) // - Wrong keyset because of programming error. var dek = deks.SingleOrDefault(d => d.Id == input.DekId) ?? throw new InvalidOperationException("Required key not found"); Span key = stackalloc byte[dekCryptor.GetDecryptedSize(dek.KeyData)]; try { dekCryptor.Decrypt(dek.KeyData, key); byte[] output = new byte[Encryption.GetDecryptedLength(input.Value)]; Encryption.Decrypt(input.Value, key, output); return output; } finally { CryptographicOperations.ZeroMemory(key); } } }