Files
emall-api/FutureMailAPI/Helpers/PasswordHelper.cs
2025-10-16 15:21:52 +08:00

119 lines
4.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Security.Cryptography;
using System.Text;
namespace FutureMailAPI.Helpers
{
public interface IPasswordHelper
{
string HashPassword(string password);
bool VerifyPassword(string password, string hash);
bool VerifyPassword(string password, string hash, string salt);
string HashPassword(string password, string salt);
string GenerateSalt();
}
public class PasswordHelper : IPasswordHelper
{
public string HashPassword(string password)
{
// 生成随机盐值
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
// 使用PBKDF2算法生成哈希
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] hash = pbkdf2.GetBytes(20);
// 组合盐值和哈希值
byte[] hashBytes = new byte[36];
Array.Copy(salt, 0, hashBytes, 0, 16);
Array.Copy(hash, 0, hashBytes, 16, 20);
// 转换为Base64字符串
return Convert.ToBase64String(hashBytes);
}
public string GenerateSalt()
{
// 生成随机盐值
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[16]);
// 转换为Base64字符串
return Convert.ToBase64String(salt);
}
public string HashPassword(string password, string salt)
{
// 将Base64盐值转换为字节数组
byte[] saltBytes = Convert.FromBase64String(salt);
// 使用PBKDF2算法生成哈希
var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, 10000);
byte[] hash = pbkdf2.GetBytes(20);
// 转换为Base64字符串
return Convert.ToBase64String(hash);
}
public bool VerifyPassword(string password, string hash)
{
try
{
// 检查哈希长度判断是完整哈希36字节还是纯哈希20字节
byte[] hashBytes = Convert.FromBase64String(hash);
if (hashBytes.Length == 36)
{
// 完整哈希格式:盐值(16字节) + 哈希值(20字节)
byte[] salt = new byte[16];
Array.Copy(hashBytes, 0, salt, 0, 16);
// 使用相同的盐值计算密码的哈希
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 10000);
byte[] computedHash = pbkdf2.GetBytes(20);
// 比较两个哈希值
for (int i = 0; i < 20; i++)
{
if (hashBytes[i + 16] != computedHash[i])
return false;
}
return true;
}
else if (hashBytes.Length == 20)
{
// 纯哈希格式:只有哈希值(20字节)
// 这种情况下,我们需要从数据库中获取盐值
// 但由于VerifyPassword方法没有盐值参数我们无法验证这种格式
// 返回false表示验证失败
return false;
}
else
{
// 未知的哈希格式
return false;
}
}
catch
{
return false;
}
}
public bool VerifyPassword(string password, string hash, string salt)
{
try
{
// 使用提供的盐值计算密码的哈希
var computedHash = HashPassword(password, salt);
return hash == computedHash;
}
catch
{
return false;
}
}
}
}