簡體   English   中英

如何使用 Ruby 檢查 SHA1 用戶名、密碼和驗證程序/鹽是否正確?

[英]How can I with Ruby check if SHA1 username, password and verifier/salt is correct?

大家好,這是我在這里的第一篇文章。

我有一個用戶名,密碼和這個驗證器,鹽。 如何檢查 Ruby 是否正確?

我遵循的文檔/說明是這樣的: https://www.azerothcore.org/wiki/account

我的代碼 atm 如下所示:

class Account < ApplicationRecord
 self.table_name = "account"
 def self.check_username_password(username, password)
  account = Account.find_by(username: username)
  h1 = Digest::SHA1.hexdigest(username.uppercase + password.uppercase)
  h2 = Digest::SHA1.hexdigest( account.salt + ..... )
  h2 == account.verifier
 end
end

您鏈接的文檔描述了計算驗證者的算法:

驗證者

verifier 派生自 salt,以及用戶的用戶名(全部大寫)和他們的密碼(全部大寫)。

要獲得驗證者,您需要計算:

計算 h1 = SHA1("USERNAME:PASSWORD"),將用戶的用戶名和密碼替換為大寫。

計算 h2 = SHA1(salt || h1),其中 || 是連接(PHP 中的 . 運算符)。

注意:salt 和 h1 都是二進制,而不是十六進制字符串!

將 h2 視為 integer 以 little-endian 順序(第一個字節是最低有效字節)。

計算 (g ^ h2) % N。

注意:g 和 N 是參數,在 WoW 實現中是固定的。

g = 7

N = 0x894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7

以 little-endian 順序將結果轉換回字節數組。

根據示例實現的鏈接,這似乎是來自 SRP6 的驗證程序,您可能可以將此 gem 用於: https://github.com/grempe/sirp 但是,它與文檔並不完全一致,我認為這可能很有趣,所以無論如何我都會嘗試完成它。

首先,您已經開始查找h1h2 ,但是正如注釋所說, Both salt and h1 are binary, not hexadecimal strings! . 因此,您需要將hexdigest替換為digest 此外, upcase中的大寫方法是大寫的,您需要在兩者之間加一個冒號:

h1 = Digest::SHA1.digest("#{username.upcase}:#{password.upcase}")
h2 = Digest::SHA1.digest(account.salt + h1)

接下來,它將 h2 轉換為 integer,就好像它存儲在 little-endian 中一樣。 請記住,整數存儲為字節序列,每個字節為 8 位; 所以 32 位 integer 是 4 個字節。 字節序描述了第一個字節是映射到數字的前 8 位還是后 8 位。 在這里,評論清楚地表明這將是最后一次。 現在,SHA1 生成一個 20 字節的 hash,所以我們將使用unpack方法加上H指令(匹配每個十六進制字節)來得到它。 這部分可能是錯誤的,所以如果您的驗證器仍然不匹配,請嘗試注釋掉的替代版本。

h2_int = h2.reverse.unpack("H*").first.to_i(16)

# alternate version, treating the first byte as most significant:
#
# h2_int = h2.unpack("H*").first.to_i(16)

最后,我們對給定的常量進行一些數學運算並將其轉換回字符串。 ^ %結構必須是模冪運算,您可以在 Ruby 2.5+ 中僅使用Integer#pow或在 Ruby 2.4 中使用 openssl 的mod_exp

g = 7
N = 0x894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7

verifier_int = g.pow(h2_int, N)

# ruby 2.4 or below:
#
# require 'openssl'
# verifier_int = g.to_bn.mod_exp(h2_int, N).to_i

verifier = [verifier_int.to_s(16)].pack('H*').reverse

# alternate version, if the above alternate version is also needed:
#
# verifier = [verifier_int.to_s(16)].pack('H*')

把它們放在一起:

h1 = Digest::SHA1.digest("#{username.upcase}:#{password.upcase}")
h2 = Digest::SHA1.digest(account.salt + h1)

h2_int = h2.reverse.unpack("H*").first.to_i(16)

# alternate version, treating the first byte as most significant:
#
# h2_int = h2.unpack("H*").first.to_i(16)

g = 7
N = 0x894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7

verifier_int = g.pow(h2_int, N)

# ruby 2.4 or below:
#
# require 'openssl'
# verifier_int = g.to_bn.mod_exp(h2_int, N).to_i

verifier = [verifier_int.to_s(16)].pack('H*').reverse

# alternate version, if the above alternate version is also needed:
#
# verifier = [verifier_int.to_s(16)].pack('H*')

這可能是錯誤的,但為了進行更多調試,我需要一個示例用戶名和密碼驗證器(但不是來自真實帳戶。)。

暫無
暫無

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

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