2026-02-26 16:53:02 +01:00
|
|
|
|
using IdentityShroud.Core.Contracts;
|
|
|
|
|
|
using IdentityShroud.Core.Security;
|
|
|
|
|
|
|
|
|
|
|
|
namespace IdentityShroud.Core.Services;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
///
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class DekEncryptionService : IDekEncryptionService
|
|
|
|
|
|
{
|
|
|
|
|
|
// Note this array is expected to have one item in it most of the during key rotation it will have two
|
|
|
|
|
|
// until it is ensured the old key can safely be removed. More then two will work but is not really expected.
|
|
|
|
|
|
private readonly KeyEncryptionKey[] _encryptionKeys;
|
|
|
|
|
|
|
|
|
|
|
|
private KeyEncryptionKey ActiveKey => _encryptionKeys.Single(k => k.Active);
|
|
|
|
|
|
private KeyEncryptionKey GetKey(KekId keyId) => _encryptionKeys.Single(k => k.Id == keyId);
|
|
|
|
|
|
|
|
|
|
|
|
public DekEncryptionService(ISecretProvider secretProvider)
|
|
|
|
|
|
{
|
|
|
|
|
|
_encryptionKeys = secretProvider.GetKeys("master");
|
|
|
|
|
|
// if (_encryptionKey.Length != 32) // 256‑bit key
|
|
|
|
|
|
// throw new Exception("Key must be 256 bits (32 bytes) for AES‑256‑GCM.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-26 20:39:48 +01:00
|
|
|
|
public EncryptedDek Encrypt(ReadOnlySpan<byte> plaintext)
|
2026-02-26 16:53:02 +01:00
|
|
|
|
{
|
|
|
|
|
|
var encryptionKey = ActiveKey;
|
|
|
|
|
|
byte[] cipher = Encryption.Encrypt(plaintext, encryptionKey.Key);
|
|
|
|
|
|
return new (encryptionKey.Id, cipher);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public byte[] Decrypt(EncryptedDek input)
|
|
|
|
|
|
{
|
|
|
|
|
|
var encryptionKey = GetKey(input.KekId);
|
|
|
|
|
|
|
|
|
|
|
|
return Encryption.Decrypt(input.Value, encryptionKey.Key);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|