我有一个python代码,它使用PBKDF2方法生成密码的sha1散列。然后,我在一个dotnet framework 4.5程序中使用这个密码摘要来根据相同的密码验证它。C#程序返回false,这意味着从python程序生成的散列是不正确的。
关键是这种格式:#iterations|salt|key。然后,我接受这个密钥,并尝试使用一个使用via方法的dotnet框架应用程序来验证它:
public static bool IsValid(string testPassword, string originalDelimitedHash)
{
//extract original values from delimited hash text
var originalHashParts = originalDelimitedHash.Split('|');
var origIterations = Int32.Parse(originalHashParts[0]);
var origSalt = Convert.FromBase64String(originalHashParts[1]);
var originalHash = originalHashParts[2];
//generate hash from test password and original salt and iterations
var pbkdf2 = new Rfc2898DeriveBytes(testPassword, origSalt, origIterations, HashAlgorithmName.SHA1);
byte[] testHash = pbkdf2.GetBytes(20);
var hashStr = Convert.ToBase64String(testHash);
if (hashStr == originalHash)
return true;
return false;
}我的python程序:
from hashlib import pbkdf2_hmac
from base64 import b64encode
from os import urandom
def generate_password_hash(password:string):
encodedPass = password.encode('utf8')
random_bytes = urandom(20)
salt = b64encode(random_bytes)
iterations = 5000
key = pbkdf2_hmac('sha1', encodedPass, salt, iterations, dklen=20)
result = f'{iterations}|{salt.decode("utf-8")}|{binascii.hexlify(key).decode("utf-8")}'
return result因此,如果我的密码是hDHzJnMg0O,那么上面的python方法产生的摘要将类似于5000|J5avBy0q5p9R/6cgxUpu6+6sW7o=|2445594504c9ffb54d1f11bbd0b385e3e37a5aca
因此,如果我将其提供给我的C# IsValid方法(参见下面),它将返回false,这意味着密码不匹配
static void Main(string[] args)
{
var pass = "hDHzJnMg0O";
var hash = "5000|J5avBy0q5p9R/6cgxUpu6+6sW7o=|2445594504c9ffb54d1f11bbd0b385e3e37a5aca";
var isValid = IsValid(pass, hash); // returns False
}发布于 2022-07-28 17:10:31
Python代码:
b64encode(random_bytes)作为PBKDF2调用的salt。这是相当不寻常的(但不是一个bug)。通常,原始数据(即random_bytes )作为salt应用并传递给PBKDF2调用。使用Base64编码,将只创建字符串。C#代码在这些点上是不同的,并且:
decoded.
random_bytes )来进行PBKDF2调用,也就是说,来自Python端的salt是Base64
。
为了与Python代码兼容而更改C#代码(当然,也可以在Python代码中进行更改,但Python代码似乎是参考):
...
var origSalt = Encoding.UTF8.GetBytes(originalHashParts[1]); // Convert.FromBase64String(originalHashParts[1]);
...
var hashStr = Convert.ToHexString(testHash); // Convert.ToBase64String(testHash);
...对于后者,使用了Convert.ToHexString(),这在.NET 5之后就可以使用了。
此外,由于对十六进制编码的值进行了比较,对于小写字母(例如binascii.hexlify(key))和大写字母(例如Convert.ToHexString(testHash)),不同的实现没有标准化,因此统一地转换这两个字符串是更可靠的,例如:
if (hashStr.ToUpper() == originalHash.ToUpper())
return true;通过这些更改,使用C#代码进行验证是可行的。
编辑(关于注释中处理的Python代码的更改):
如果在Python中使用random_bytes作为salt,而salt被编码为Base64以进行级联,那么在C#代码中,必须再次对Base64编码的salt进行Base64解码(与原始C#代码一样)。
https://stackoverflow.com/questions/73151352
复制相似问题