如何用HMACSHA512验证用户密码?哈希匹配失败问题求助
密码哈希验证失败的问题排查与修复
问题描述
我正在编写一个验证方法,用于验证通过HMACSHA512生成的用户密码。该方法接收待验证密码,以及从数据库中获取的原密码哈希值和盐值。但同一密码通过ComputeHash()生成的哈希值,始终与数据库中存储的原哈希值不一致。
验证方法代码
private bool VerifyPasswordHash(string passwordToVerify, byte[] oldUserPasswordHash, byte[] existingPswSalt) { bool isSame = false; using (HMACSHA512 hasher = new HMACSHA512(existingPswSalt)) { // 生成的新哈希与原哈希不同 byte[] pswHash = hasher.ComputeHash(Encoding.UTF8.GetBytes(passwordToVerify)); isSame = pswHash.SequenceEqual(oldUserPasswordHash); } return isSame; }
哈希与盐值生成方法代码
private (byte[] PswHash, byte[] PswSalt) CreatePasswordHashAndSalt(string password) { byte[] pswSalt; byte[] pswHash; using (HMACSHA512 hmac = new HMACSHA512()) { pswSalt = hmac.Key; pswHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(password)); } return (pswHash, pswSalt); }
问题原因
核心问题大概率是盐值或哈希值的存储/读取过程中字节数组被损坏:
- 随机生成的盐值(
hmac.Key)是纯字节序列,并非合法的UTF-8字符串。如果存储时直接用Encoding.UTF8.GetString()将字节数组转成字符串,会导致部分字节无法被UTF-8解析,转换为乱码或丢失信息;读取时再转回字节数组,就会和原盐值不一致。 - 用错误的方式转换哈希值也会导致同样的问题,最终验证时使用了错误的盐值,自然生成的哈希与原哈希不匹配。
修复方案
1. 存储时用Base64编码转换字节数组
Base64是专门用于将任意字节序列转换为可安全存储/传输字符串的编码方式,不会丢失字节信息。
// 生成哈希和盐值 var (hashBytes, saltBytes) = CreatePasswordHashAndSalt("userPassword"); // 转换为Base64字符串存入数据库 string storedHash = Convert.ToBase64String(hashBytes); string storedSalt = Convert.ToBase64String(saltBytes);
2. 验证时将Base64字符串转回字节数组
从数据库取出存储的字符串后,先转回字节数组再传入验证方法:
// 从数据库读取Base64格式的哈希和盐值 string storedHash = ...; string storedSalt = ...; // 转回字节数组 byte[] hashBytes = Convert.FromBase64String(storedHash); byte[] saltBytes = Convert.FromBase64String(storedSalt); // 执行验证 bool isPasswordValid = VerifyPasswordHash("userPassword", hashBytes, saltBytes);
3. 额外检查项
- 确认验证方法中传入的
existingPswSalt和oldUserPasswordHash确实是从数据库正确读取并转换后的字节数组,没有被截断或篡改。 - 确保生成和验证时,密码转字节数组的编码完全一致(你的代码中已统一用
Encoding.UTF8.GetBytes(),无需修改)。
内容的提问来源于stack exchange,提问作者Val
相关产品推荐
相关产品推荐

