aegis-api/Aegis.Infrastructure/Crypto/ServerSecretLabelKeyProvider.cs

58 lines
1.7 KiB
C#

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<byte>();
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;
}
}