Files

48 lines
1.7 KiB
C#

using System.Security.Cryptography;
using System.Text;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Options;
public class PhiEncryptionService : IPhiEncryptionService
{
private readonly IDataProtector _protector;
private readonly byte[] _searchKey;
public PhiEncryptionService(
IDataProtectionProvider provider,
IOptions<PhiEncryptionOptions> options)
{
var opts = options.Value;
_protector = provider.CreateProtector(opts.ProtectorPurpose);
_searchKey = Convert.FromBase64String(
Convert.ToBase64String(Encoding.UTF8.GetBytes(opts.SearchTokenKey))[..44]); // normalize dev key
}
public string Encrypt(string plaintext)
{
if (string.IsNullOrEmpty(plaintext))
return plaintext;
return _protector.Protect(plaintext);
}
public string Decrypt(string ciphertext)
{
if (string.IsNullOrEmpty(ciphertext))
return ciphertext;
if (!IsEncrypted(ciphertext))
return ciphertext; // migration transition: plaintext rows still readable
return _protector.Unprotect(ciphertext);
}
public bool IsEncrypted(string value) =>
value.StartsWith("CfDJ8", StringComparison.Ordinal) || // DataProtection prefix
value.Length > 50; // heuristic for protected payloads
public string ComputeNameSearchToken(string firstName, string lastName)
{
var normalized = $"{firstName.Trim().ToLowerInvariant()}|{lastName.Trim().ToLowerInvariant()}";
using var hmac = new HMACSHA256(_searchKey);
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(normalized));
return Convert.ToHexString(hash).ToLowerInvariant();
}
}