2017-05-16 24 views
0

我們有一個擁有數千個傳統密碼哈希的客戶端,他們希望我們能夠驗證/匹配,以便將這些登錄名移至更現代的安全考慮事項。使用PHP重新生成ASP SHA1 salt/hash

的散列SHA1樣(十六進制和40個字符),而在ASP.NET產生。我們有幾個測試用例,它們都有明文密碼,base64編碼的鹽和base64編碼的散列 - 我們需要能夠根據給定的密碼和salt重新生成散列。

我一直在使用https://forums.asp.net/p/1336657/2899172.aspx作爲參考來寫一個PHP腳本重現哈希值。下面是我想直接重寫代碼片段:

public string EncodePassword(string pass, string saltBase64) 
{ 
    byte[] bytes = Encoding.Unicode.GetBytes(pass); 
    byte[] src = Convert.FromBase64String(saltBase64); 
    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); 
} 

這看起來非常簡單 - 獲取密碼,基於64位解碼鹽的字節數組,將它們連接起來,並通過SHA1運行它們。我覺得我有90%的方式,但我無法成功地匹配提供的哈希,無論我嘗試什麼變體!

我懷疑我在再現Encoding.Unicode.GetBytes嘗試是問題 - unpack可能是不等價的。但是經過一個多小時的搜索,我找不到任何接近的方法。不是一個ASP開發人員,我敢肯定,我錯過了一些細微差別 - 任何人都可以指出哪裏出錯了?

這裏是我的測試輸出代碼:

$test = [ 
    'plaintext' => 'overthis2:)', 
    'salt' => '7LeJR68EGhBgaE7EYgL/gg==', 
    'hash' => 'g54KVV4Wj5smOyXHOReyWnTnGDc=' 
]; 
$algos = [ 'sha1', 'ripemd160', 'tiger160,3', 'tiger160,4', 'haval160,3', 'haval160,4', 'haval160,5' ]; 
$raw = implode('', unpack("H*", $test['plaintext'])) . base64_decode($test['salt']); 

echo 'Plaintext:  ' . $test['plaintext'] . "\n"; 
echo 'Salt:   ' . $test['salt'] . "\n"; 
echo 'Raw:   ' . $raw . "\n\n"; 
echo 'Saved hash: ' . $test['hash'] . "\n"; 
echo 'Decoded:  ' . bin2hex(base64_decode($test['hash'])) . "\n\n"; 

foreach ($algos as $algo) { 
    echo str_pad($algo . ':' , 15, ' ') . hash($algo, $raw) . "\n"; 
} 

下面是它得到的結果 - 沒有一個散列的匹配提供:

Plaintext:  overthis2:) 
Salt:   7LeJR68EGhBgaE7EYgL/gg== 
Raw:   6f76657274686973323a29췉G�`hN�b�� 

Saved hash: g54KVV4Wj5smOyXHOReyWnTnGDc= 
Decoded:  839e0a555e168f9b263b25c73917b25a74e71837 

sha1:   d0b448e50d81e6a42601ebcc8e7aa07423d12210 
ripemd160:  4359afa37173388db43c47db5188cf5cc47f30d9 
tiger160,3: c2e22500127cef7141077049e9bda7747e0b298d 
tiger160,4: e03fc57f1d9259cd650aab3682cf54609a30d62b 
haval160,3: 437838726fc63fb15969e1c5f0b34dc7f404cabc 
haval160,4: ec5cb7e38fe28534b65d25fabf756113c9e563d6 
haval160,5: 48551660bbc519bb7db8d595556f4f167eeec749 
+0

因爲它是一個散列,所以你將無法複製。你可以做的是設置表格以保存另一列,檢查它們是否有新的散列。如果沒有,請檢查沒有散列或舊散列,然後創建一個新的散列w /'password_hash()'。 –

+0

@JayBlanchard它應該產生相同的散列給定的輸入(如果正確),對不對? SHA1-ing'test'將始終提供'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'。看到[這個答案](https://security.stackexchange.com/a/31880/142141) –

+0

@JayBlanchard感謝您的輸入,但這不是真的 - SHA1是一對一的轉換,相同的字符串總是產生相同的散列。我只是缺少ASP.NET如何創建預先哈希的密碼/鹽的組件。你能透露一下我錯過的東西嗎? – CodeMoose

回答

2

的.NET代碼處理密碼utf16le應按字符串(Encoding.Unicode ),所以每個字符都是16位寬。這意味着在這種情況下,該部分中的每個其他字節都是零。

你也有鹽和密碼錯誤的方式周圍並沒有需要解壓的話,就是.NET代碼沒有使用十六進制值,而原始字節。

讓這種變化,你會得到相同的哈希值:

$raw = base64_decode($test['salt']).implode("\0", str_split($test['plaintext']))."\0"; 

這只是取鹽,對其進行解碼,然後將其密碼由每個字符後增加一個零字節轉換爲UTF-16,這就是它。

+0

這確實解決了我的問題 - 非常感謝! – CodeMoose