using System.Security.Cryptography;
using System.Text;
namespace Service.Implement
{
///
/// 密码哈希工具(PBKDF2-SHA256,格式 salt$hash,盐随机 16 字节)
///
public static class PasswordHelper
{
private const int Iterations = 10_000;
private const int SaltSize = 16;
private const int HashSize = 32;
/// 生成密码哈希(salt$hash)
public static string Hash(string password)
{
var salt = RandomNumberGenerator.GetBytes(SaltSize);
var hash = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, HashAlgorithmName.SHA256, HashSize);
return $"{Convert.ToHexString(salt)}${Convert.ToHexString(hash)}";
}
/// 校验密码是否匹配
public static bool Verify(string password, string? stored)
{
if (string.IsNullOrWhiteSpace(stored)) return false;
var parts = stored.Split('$');
if (parts.Length != 2) return false;
var salt = Convert.FromHexString(parts[0]);
var expected = Convert.FromHexString(parts[1]);
var actual = Rfc2898DeriveBytes.Pbkdf2(password, salt, Iterations, HashAlgorithmName.SHA256, expected.Length);
return CryptographicOperations.FixedTimeEquals(actual, expected);
}
/// 生成随机盐字符串(供外部使用)
public static string NewSalt()
{
var salt = RandomNumberGenerator.GetBytes(SaltSize);
return Convert.ToHexString(salt).ToLowerInvariant();
}
/// SHA256(供 RefreshToken 等场景)
public static string Sha256(string input)
{
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(input));
return Convert.ToHexString(bytes).ToLowerInvariant();
}
}
}