【问题标题】:How can I verify a plaintext password with a hash algorithm?如何使用哈希算法验证明文密码?
【发布时间】:2011-06-13 21:06:00
【问题描述】:

我有一个关于盐的问题。例如,我们的记录中有 看起来像这样的数据库:

Password: YUphoRF70vJEPAOjMmc/9n47hyQ= 
Password Format: 1 
Password Salt: Vx37L8ItQo3rJzx5gRCxTw==

我正在尝试验证此密码,但我使用的方法不起作用。

这是方法:

public static string EncodePassword(string pass, string salt)
{
    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] src = Encoding.Unicode.GetBytes(salt);
    byte[] dst = new byte[src.Length + bytes.Length];
    Buffer.BlockCopy(src, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
    HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
    byte[] inArray = algorithm.ComputeHash(dst);
    return Convert.ToBase64String(inArray);
}

我是这样传递的:

string encodedPasswd = Cryptography.EncodePassword(ClearTxtPassword, DbPasswordSalt);

返回的内容看起来不像数据库中的密码。

我想知道我是否应该对盐做些其他事情?是 存储在数据库中的内容我应该传递给 EncodePassword 方法还是 中间有一个步骤,我应该在将其作为 范围?

我只是不确定为什么会出现密码不匹配的情况。根据我正在处理的网站的 web.config,它是 passwordFormat="Hashed",数据库中的 PasswordFormat 列显示为“1”,所以我知道它是 SHA1。

你有什么想法为什么我没有得到正确的匹配,或者如何进一步解决它?(是的,我有正确的密码。)

编辑:

我尝试了以下更新方法:

public static string EncodePassword(string pass, string salt)
{
    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] src = Convert.FromBase64String(salt);
    byte[] dst = new byte[src.Length + bytes.Length];
    Buffer.BlockCopy(src, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
    HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
    byte[] inArray = algorithm.ComputeHash(dst);
    return Convert.ToBase64String(inArray);
}

与我当前的数据库数据相比,它仍然不匹配。例如,我得到 结果如下:

passwordText = "administrator"
passwordformat: 1 / SHA1
passwordSaltInDb: "zVhahfmXj9MrOQySyPQ1Qw=="
passwordInDb = "YZ5xRJkNG9erGStAkWJA3hID9vE="


encodedPasswordResults = "DWZ6XRtVMy4l+XSUOKoX8usUOJI="

是否有人可以在他们自己的环境中进行测试以了解为什么我会得到如此不同的结果?

【问题讨论】:

  • 您永远不应该解密密码。将输入密码的散列/加盐值与存储的散列/加盐值进行比较。
  • 谢谢科迪 - 同意。这就是我试图做的——只是没有很好地描述问题。正在尝试验证明文密码。
  • 你确定它只是 SHA1 的一次迭代吗?在密码散列函数中,对散列进行数千次迭代是很常见的。 salt和密码之间应该有分隔符吗?
  • 这还开着吗?看来您必须找出最初创建加盐密码的方式,然后复制此方法。猜测正确的算法没有多大意义。
  • 对于如何应用盐以及如何编码参数,几乎有无数种细微的变化。如果没有关于所用程序的良好文档,我认为您不会完成这项工作。

标签: c# hash cryptography passwords


【解决方案1】:

SHA1 不易解密,这也是它用于存储密码的原因之一。为什么要尝试解密密码?

【讨论】:

  • 是的,谢谢 Rob。正如 LukeH 所指出的,我使用了错误的措辞。我正在尝试“验证”明文密码。请查看我的编辑 - 你能提供进一步的建议吗?
【解决方案2】:

如果您传递的盐与存储在数据库中的盐完全一样,那么您正在处理的是 Base-64 编码的字符串。要将其转换为byte[] 数组,您应该使用Convert.FromBase64String 而不是Unicode.GetBytes。大致如下:

public static string EncodePassword(string pass, string salt)
{
    byte[] bytes = Encoding.Unicode.GetBytes(pass);
    byte[] src = Convert.FromBase64String(salt);
    byte[] dst = new byte[src.Length + bytes.Length];
    Buffer.BlockCopy(src, 0, dst, 0, src.Length);
    Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
    HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
    byte[] inArray = algorithm.ComputeHash(dst);
    return Convert.ToBase64String(inArray);
}

顺便说一句,尽管您的问题反复提到解密密码,但在我看来,您似乎只是在尝试针对存储的哈希验证明文密码。如果是这样,那么上面的代码应该没问题。

如果您真的想解密存储的哈希值,请不要打扰!哈希不是密码的加密版本,因此无法解密。

【讨论】:

  • 谢谢 LukeH... 是的,你是对的。我在谈论明文密码验证——那是我的错。我已经尝试了您的更新方法并发布了我的更新 - 它仍然无法正常工作。你有机会测试这个吗?还有什么想法吗?
  • 关于您的更新...我已经尝试使用您的示例数据运行代码 -- "administrator""zVhahfmXj9MrOQySyPQ1Qw==" - 并且无法匹配您示例中的 passwordInDbencodedPasswordResults。你确定明文密码应该是“administrator”