Files
emall-api/FutureMailAPI/Helpers/PasswordHelper.cs

119 lines
4.0 KiB
C#
Raw Normal View History

2025-10-16 09:56:36 +08:00
using System.Security.Cryptography;
using System.Text;
namespace FutureMailAPI.Helpers
{
public interface IPasswordHelper
{
string HashPassword(string password);
bool VerifyPassword(string password, string hash);
2025-10-16 15:21:52 +08:00
bool VerifyPassword(string password, string hash, string salt);
2025-10-16 09:56:36 +08:00
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
{
2025-10-16 15:21:52 +08:00
// 检查哈希长度判断是完整哈希36字节还是纯哈希20字节
2025-10-16 09:56:36 +08:00
byte[] hashBytes = Convert.FromBase64String(hash);
2025-10-16 15:21:52 +08:00
if (hashBytes.Length == 36)
2025-10-16 09:56:36 +08:00
{
2025-10-16 15:21:52 +08:00
// 完整哈希格式:盐值(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;
2025-10-16 09:56:36 +08:00
}
2025-10-16 15:21:52 +08:00
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;
2025-10-16 09:56:36 +08:00
}
catch
{
return false;
}
}
}
}