using System.Security.Cryptography; using System.Text; namespace Aegis.Repository.Crypto; public class ServerSecretLabelKeyProvider : ILabelKeyProvider { private readonly byte[] _serverSecret; public ServerSecretLabelKeyProvider(byte[] serverSecret) { if (serverSecret.Length < 32) throw new ArgumentException("Server secret deve ter pelo menos 32 bytes."); _serverSecret = serverSecret; } public byte[] GetLabelKey(string lkKid, int lkVersion) { // HKDF simples via HMACSHA256 (ok para derivação) // info amarra ao kid+version var info = Encoding.UTF8.GetBytes($"aegis:lk:{lkKid}:v{lkVersion}"); return HkdfSha256(_serverSecret, salt: null, info, 32); } private static byte[] HkdfSha256(byte[] ikm, byte[]? salt, byte[] info, int len) { salt ??= new byte[32]; // salt zero (ok se ikm for segredo forte) using var hmac = new HMACSHA256(salt); var prk = hmac.ComputeHash(ikm); var okm = new byte[len]; byte[] t = Array.Empty(); var pos = 0; byte counter = 1; using var hmac2 = new HMACSHA256(prk); while (pos < len) { var input = new byte[t.Length + info.Length + 1]; Buffer.BlockCopy(t, 0, input, 0, t.Length); Buffer.BlockCopy(info, 0, input, t.Length, info.Length); input[^1] = counter; t = hmac2.ComputeHash(input); var take = Math.Min(t.Length, len - pos); Buffer.BlockCopy(t, 0, okm, pos, take); pos += take; counter++; } CryptographicOperations.ZeroMemory(prk); CryptographicOperations.ZeroMemory(t); return okm; } }