在.NET中验证Python Passlib生成的PBKDF2 SHA512哈希值

3

我正在迁移一个使用 Passlib 1.6.2 生成密码哈希的平台。加密密码的代码如下(使用默认值进行轮数调用哈希函数):

from passlib.hash import pbkdf2_sha512 as pb

def hash(cleartext, rounds=10001):
    return pb.encrypt(cleartext, rounds=rounds)

输出格式看起来像(对于密码“Patient3”(不带引号)):
$pbkdf2-sha512$10001$0dr7v7eWUmptrfW.9z6HkA$w9j9AMVmKAP17OosCqDxDv2hjsvzlLpF8Rra8I7p/b5746rghZ8WrgEjDpvXG5hLz1UeNLzgFa81Drbx2b7.hg

并且是 "测试123"

$pbkdf2-sha512$10001$2ZuTslYKAYDQGiPkfA.B8A$ChsEXEjanEToQcPJiuVaKk0Ls3n0YK7gnxsu59rxWOawl/iKgo0XSWyaAfhFV0.Yu3QqfehB4dc7yGGsIW.ARQ

我看到的表示为:
  • 算法 SHA512
  • 迭代次数 10001
  • 盐值 0dr7v7eWUmptrfW.9z6HkA(可能)
Passlib 算法在其网站上定义,具体内容请参见 此处,其格式为:

所有由 Passlib 定义的 pbkdf2 哈希都遵循相同的格式:$pbkdf2-digest$rounds$salt$checksum。

$pbkdf2-digest$ 用作模块化加密格式标识符(例如,在本例中为 $pbkdf2-sha256$)。 digest - 这指定了与 HMAC 结合使用以形成 PBKDF2 的伪随机函数的特定加密哈希(在本例中为 sha256)。 rounds - 应执行的迭代次数。这被编码为没有零填充的正十进制数(在本例中为 6400)。 salt - 这是传递到 PBKDF2 函数的原始盐字节的适应的 base64 编码。 checksum - 这是从 PBKDF2 函数返回的原始派生键字节的适应的 base64 编码。每个方案都将其特定哈希算法(digest)的摘要大小用作原始派生密钥的大小。这通过 base64 编码增大了约 4/3,从而产生了每个列出的算法的 27、43 和 86 的校验和大小。

我发现 passlib.net 看起来有点像被放弃的 beta 版本,并且它使用 '$6$' 作为算法。我无法验证密码。我尝试将算法更改为 $6$,但我怀疑这实际上也会更改盐。
我还尝试过使用 PWDTK 并提供不同的盐值和哈希值,但可能是我在错误地拆分阴影密码,或者在某些地方提供了 $,导致无法成功操作。
是否有任何方法可以在 .NET 中根据此哈希值验证密码?或者其他不需要使用 Python 代理或让用户重新输入密码的解决方案?

@zaph 我不知道不同的库如何处理编码和空格,我需要了解这些方面的具体指导。 - JohnMark13
1
提供密码输入到示例中。 - zaph
除了输入:“pb”是什么?请提供一个MCVE - Artjom B.
对于密码 "Patient3",输出确切地是 "$pbkdf2 - sha512$10001$0dr7v7eWUmptrfW.9z6HkA$w9j9AMVmKAP17OosCqDxDv2hjsvzlLpF8Rra8I7p/b5746rghZ8WrgEjDpvXG5hLz1UeNLzgFa81Drbx2b7.hg"。 - zaph
@ArtjomB。我不知道为什么我还要添加这一小行代码,问题实际上是:“鉴于这个影子密码,在.NET中如何验证明文密码?” - JohnMark13
显示剩余4条评论
2个回答

2

我很快地使用zaph的逻辑和JimmiTh在SO answer中的代码,拼凑出了一个.NET实现。我已经将代码放在GitHub上(这不应该是生产就绪的)。它似乎可以处理我们用户群体中的许多示例。

正如zaph所说的那样,逻辑是:

  1. 将哈希分割以查找迭代次数、盐和哈希密码(我已经假定了算法,但你需要验证)。您将获得一个包含5个值的数组,其中 [0] - 无,[1] - 算法,[2] - 迭代次数,[3] - 盐和 [4] - 哈希
  2. 通过将任何“.”字符替换为“+”字符并添加“==”来将盐转换为标准的Base64编码。
  3. 将密码、盐和迭代次数传递给 PBKDF2-HMAC-SHA512 生成器。
  4. 通过将任何“+”字符替换为“.”字符并删除尾部的“==”,将其转换回原始的base64格式。
  5. 将其与原始哈希(拆分字符串中的元素4)进行比较,如果它们相等,则匹配成功。

1

将密码传入PBKDF HMAC-SHA-256哈希方法进行验证,然后将生成的哈希与保存的哈希部分进行比较,从Base64版本转换回来。

将保存的哈希转换为二进制,然后分离哈希 使用UTF-8编码将密码转换为二进制 PBKDF2、HMAC、SHA-256(toBinary(password, salt, 10001) == hash) 密码:"Patient3"

$pbkdf2 - sha512$10001$0dr7v7eWUmptrfW.9z6HkA$w9j9AMVmKAP17OosCqDxDv2hjsvzlLpF8Rra8I7p/b5746rghZ8WrgEjDpvXG5hLz1UeNLzgFa81Drbx2b7.hg

拆分为(字符串转换为标准Base64(将“。”改为“+”并添加尾随的“=”填充:

pbkdf2 - sha512
10001
0dr7v7eWUmptrfW+9z6HkA==
w9j9AMVmKAP17OosCqDxDv2hjsvzlLpF8Rra8I7p/b5746rghZ8WrgEjDpvXG5hLz1UeNLzgFa81Drbx2b7+hg==

转换为十六进制:

D1DAFBBFB796526A6DADF5BEF73E8790
C3D8FD00C5662803F5ECEA2C0AA0F10EFDA18ECBF394BA45F11ADAF08EE9FDBE7BE3AAE0859F16AE01230E9BD71B984BCF551E34BCE015AF350EB6F1D9BEFE86

有道理:16字节(128位)的盐和64字节(512位)的SHA-512哈希。

使用UTF-8将“Patient3”转换为二进制数组 将盐从修改后的BASE64编码转换为16字节的二进制数组 使用迭代计数10001 使用HMAC和SHA-512将其提供给PBKDF2

我得到

C3D8FD00C5662803F5ECEA2C0AA0F10EFDA18ECBF394BA45F11ADAF08EE9FDBE7BE3AAE0859F16AE01230E9BD71B984BCF551E34BCE015AF350EB6F1D9BEFE86

将其进行Base64编码,将'+'替换为'.',去除末尾的'='字符,得到以下结果: w9j9AMVmKAP17OosCqDxDv2hjsvzlLpF8Rra8I7p/b5746rghZ8WrgEjDpvXG5hLz1UeNLzgFa81Drbx2b7.hg


我打算写一个小的Java应用程序来测试,因为我在.NET方面失败了,谢谢你的指导,正是我所需要的。 - JohnMark13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接