using System.Security.Cryptography;
using System.Text;
using CareFix.Api.Options;
using Microsoft.Extensions.Options;
namespace CareFix.Api.Security;
/// AES-256-GCM encryption for hospital SQL passwords. Layout: nonce(12) | tag(16) | ciphertext.
public sealed class CredentialVault
{
private readonly byte[] _key;
public CredentialVault(IOptions options)
{
try { _key = Convert.FromBase64String(options.Value.MasterKey); }
catch (FormatException) { throw new InvalidOperationException("CareFix:MasterKey must be base64 (32 random bytes)."); }
if (_key.Length != 32) throw new InvalidOperationException("CareFix:MasterKey must decode to exactly 32 bytes.");
}
public byte[] Encrypt(string plain)
{
var nonce = RandomNumberGenerator.GetBytes(12);
var pt = Encoding.UTF8.GetBytes(plain);
var ct = new byte[pt.Length];
var tag = new byte[16];
using var aes = new AesGcm(_key, 16);
aes.Encrypt(nonce, pt, ct, tag);
return [.. nonce, .. tag, .. ct];
}
public string Decrypt(byte[] blob)
{
if (blob.Length < 28) throw new CryptographicException("Stored credential is corrupt.");
var pt = new byte[blob.Length - 28];
using var aes = new AesGcm(_key, 16);
aes.Decrypt(blob.AsSpan(0, 12), blob.AsSpan(28), blob.AsSpan(12, 16), pt);
return Encoding.UTF8.GetString(pt);
}
}