using System.Security.Cryptography;
using System.Text;
namespace foodmarket.Application.Common;
/// Хэширование PIN-кода кассира (PBKDF2-HMAC-SHA256 со случайной солью).
/// PIN низкоэнтропийный (4–6 цифр), поэтому защита — хэш + серверный lockout
/// (5 неверных → блок). Формат хранения: «base64(salt).base64(key)».
public static class PinHasher
{
private const int SaltSize = 16;
private const int KeySize = 32;
private const int Iterations = 100_000;
public static string Hash(string pin)
{
var salt = RandomNumberGenerator.GetBytes(SaltSize);
var key = Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(pin), salt, Iterations, HashAlgorithmName.SHA256, KeySize);
return $"{Convert.ToBase64String(salt)}.{Convert.ToBase64String(key)}";
}
public static bool Verify(string pin, string? stored)
{
if (string.IsNullOrEmpty(stored)) return false;
var parts = stored.Split('.');
if (parts.Length != 2) return false;
byte[] salt, key;
try { salt = Convert.FromBase64String(parts[0]); key = Convert.FromBase64String(parts[1]); }
catch { return false; }
var test = Rfc2898DeriveBytes.Pbkdf2(Encoding.UTF8.GetBytes(pin), salt, Iterations, HashAlgorithmName.SHA256, key.Length);
return CryptographicOperations.FixedTimeEquals(test, key);
}
/// PIN — 4–6 цифр.
public static bool IsValidPin(string? pin)
=> pin is not null && pin.Length is >= 4 and <= 6 && pin.All(char.IsDigit);
}