簡體   English   中英

在 PBKDF2 Python 中生成的 sha1 密鑰在 .NET Rfc2898 中不匹配

[英]Generated sha1 key in PBKDF2 Python do not match in .NET Rfc2898

我有一個 python 代碼,它使用hashlib.pbkdf2_hmac方法生成密碼的 PBKDF2 sha1 hash。 然后我在dotnet framework 4.5程序中使用該密碼摘要來驗證它是否與相同的密碼。 C# 程序返回 false,這表明從 python 程序生成的 hash 不正確。

密鑰采用以下格式: #iterations|salt|key 然后,我使用該密鑰並嘗試使用 dotnet 框架應用程序使用 via 方法對其進行驗證:

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
}

Python 代碼:

  • 使用b64encode(random_bytes)作為 PBKDF2 調用的鹽。 這是相當不尋常的(但不是錯誤)。 通常,原始數據(即random_bytes )作為鹽應用並傳遞給 PBKDF2 調用。 使用 Base64 編碼只會創建字符串。
  • 十六進制編碼密鑰(即 PBKDF2 調用的返回值)。

C# 代碼在這些方面有所不同,並且:

  • 使用原始數據(即來自 Python 端的random_bytes )進行 PBKDF2 調用,即來自 Python 端的鹽被 Base64 解碼。
  • Base64 對密鑰進行編碼(即PBKDF2調用的返回值)

Changes in the C# code for compatibility with the Python code (of course the changes could also be made in the Python code, but the Python code seems to be the reference):

...
var origSalt = Encoding.UTF8.GetBytes(originalHashParts[1]); // Convert.FromBase64String(originalHashParts[1]);
...
var hashStr = Convert.ToHexString(testHash); // Convert.ToBase64String(testHash);
...

對於后者,使用了Convert.ToHexString() ,它從 .NET 5 開始可用。對於其他 .NET 版本,請參見此處的示例。

此外,由於比較了十六進制編碼的值,並且不同的實現在小寫字母(例如binascii.hexlify(key) )和大寫字母(例如Convert.ToHexString(testHash) )方面沒有標准化,因此統一轉換兩個字符串更加穩健,例如:

if (hashStr.ToUpper() == originalHash.ToUpper())
    return true;

通過這些更改,可以使用 C# 代碼進行驗證。


編輯(關於評論中提到的 Python 代碼的更改):

If in the Python code random_bytes is used as salt and the salt is Base64 encoded for concatenation, then in the C# code the Base64 encoded salt must be Base64 decoded again (as in the original C# code).

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM