2014-01-11 34 views
9

我正在學習Python。我無法弄清楚爲什麼hashlib.sha512(salt + password).hexdigest()沒有給出預期的結果。hashlib vs crypt.crypt()在Python中。爲什麼不同的結果

我正在尋找相當於Ulrich Drepper的sha512crypt.c algorithm的純Python實現。 (我花了一段時間才弄清楚我在找什麼。)

根據Ubuntu 12.04系統上crypt的手冊頁,crypt使用SHA-512(因爲字符串以$ 6 $開頭)。

下面的代碼驗證當我調用Python的系統crypt(即crypt.crypt())的包裝時,行爲與預期的一樣。我想使用hashlib.sha512或其他一些Python庫來產生與crypt.crypt()相同的結果。怎麼樣?

這段代碼演示了我遇到的問題:

import hashlib, crypt 

ctype = "6" #for sha512 (see man crypt) 
salt = "qwerty" 
insalt = '${}${}$'.format(ctype, salt) 
password = "AMOROSO8282" 

value1 = hashlib.sha512(salt + password).hexdigest() #what's wrong with this one? 
value2 = crypt.crypt(password, insalt) #this one is correct on Ubuntu 12.04 
if not value1 == value2: 
    print("{}\n{}\n\n".format(value1, value2)) 

根據隱窩手冊頁,SHA-512是86個字符。上面的代碼中的crypt()調用符合此。然而,hashlib.sha512的輸出超過86個字符長,所以事情是這兩個implmentations之間的路要走......

下面是對於那些不想運行的代碼誰輸出:

051f606027bd42c1aae0d71d049fdaedbcfd28bad056597b3f908d22f91cbe7b29fd0cdda4b26956397b044ed75d50c11d0c3331d3cb157eecd9481c4480e455 
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/ 

這裏基於初始反饋的另一個嘗試。沒有成功尚未:

import hashlib, crypt, base64 

ctype = "6" #for sha512 (see man crypt) 
salt = "qwerty" 
insalt = '${}${}$'.format(ctype, salt) 
password = "AMOROSO8282" 

value1 = base64.b64encode(hashlib.sha512(salt + password).digest()) 
value2 = crypt.crypt(password, insalt) #this one is correct 
if not value1 == value2: 
    print("{}\n{}\n\n".format(value1, value2)) 
+0

是您的密碼(不包括數字)故意用葡萄牙語表示的還是一個尷尬的巧合?只是好奇':)' – JMCF125

+1

這個密碼是一個真正的密碼,從真正的被盜密碼fwiw的大型數據庫中提取。 – MountainX

+0

我明白了。如果沒有鹽,用葡萄牙語小字典制作的彩虹桌確實很容易破解。順便說一句,+1,這是一個有趣的問題,即使我不使用Python。 – JMCF125

回答

11

下面是解決方案。在另一個問題中還有更多的細節:Python implementation of sha512_crypt.c它顯示passlib的後端包含sha512_crypt的純Python實現(如果crypt.crypt()在OS上不可用,則調用Python實現)。

$ sudo的PIP安裝passlib

import passlib.hash, crypt 

ctype = "6" #for sha512 (see man crypt) 
salt = "qwerty" 
insalt = '${}${}$'.format(ctype, salt) 
password = "AMOROSO8282" 

value1 = sha512_crypt.encrypt(password, salt=salt, rounds=5000) 
value2 = crypt.crypt(password, insalt) 
if not value1 == value2: 
    print("algorithms do not match") 
print("{}\n{}\n\n".format(value1, value2)) 

這裏是輸出:

$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/ 
$6$qwerty$wZZxE91RvJb4ETR0svmCb69rVCevicDV1Fw.Y9Qyg9idcZUioEoYmOzAv23wyEiNoyMLuBLGXPSQbd5ETanmq/ 

的一個關鍵點是Passlib有一個純Python實現sha512_crypt的,當系統沒有按」,它會使用沒有當前Linux系統具有的crypt實現(例如,http://www.akkadia.org/drepper/SHA-crypt.txt)。

見PassLib這裏文檔:

passlib - 密碼哈希庫蟒蛇 - 谷歌項目託管
https://code.google.com/p/passlib/

Passlib 1.6.2文檔 - Passlib V1.6.2文檔
http://pythonhosted.org/passlib/

passlib-users - Google Groups
https://groups.google.com/forum/#!forum/passlib-users

新應用快速入門指南 - Passlib V1.6.2文檔
http://pythonhosted.org/passlib/new_app_quickstart.html#sha512-crypt

passlib.hash.sha512_crypt - SHA-512地穴 - Passlib V1.6.2文檔
http://pythonhosted.org/passlib/lib/passlib.hash.sha512_crypt.html#passlib.hash.sha512_crypt

4

您的密碼是不一樣的長度,這是因爲crypt() 輸出是base64編碼,並使用hexdigest爲value1

相反hexdigest的,你應該嘗試做這樣的事情

value1 = crypt_base64(hashlib.sha512(salt + password)) 

crypt_base64bash implementationdoHash()功能最後一部分。

+0

很好的建議,但你的答案是不夠的。你能基於我的簡單例子提供可用的Python代碼嗎?我用base64編碼更新了我的答案,但是這兩個結果仍然不匹配。 – MountainX

+1

@MountainX你錯誤地認爲bash腳本實現了「標準」b64編碼。通過從base64調用b64encode不能鬆懈地實現crypt_base64。 – 2014-01-12 08:07:02

+0

謝謝你的回答。它幫助我走上正軌。看到我的答案是「準備運行」的解決方案。 – MountainX

7

crypt的手冊不準確(甚至有誤導性)。具有「MD5」,「SHA-256」或「SHA-512」標記的crypt所使用的算法實際上是在這些基元上的算法構建的。他們是password-based key derivation functions,使用散列執行key strengthening

A good password hashing algorithm有兩個屬性:它必須將密碼與獨特的鹽組合起來(以便一次性破解嘗試破解多個密碼的嘗試),並且它必須很慢(因爲攻擊者比攻擊者傷害的更多需要嘗試大量的組合)。每日散列算法(如MD5和SHA系列)的設計儘可能快,儘可能快,同時仍具有所需的安全屬性。構建密碼哈希算法的一種方法是採用加密哈希算法並迭代多次。雖然這isn't ideal(因爲有更好的技術,使建立專用硬件密碼破解更難),這是足夠的。

Wikipedia article for crypt(3)提供了一個簡要的解釋和指向主要來源。Linux和FreeBSD的手冊頁很差,但Solaris's有足夠的信息不容誤解(請點擊鏈接到crypt.conf(4),然後crypt_sha512和其他)。您也可以閱讀Is user password in ubuntu 13.04 in plain text?Is there repetition in the Solaris 11 hash routine? Can I add some?

在Python中計算crypt的輸出的正確方法是調用crypt.crypt

+0

謝謝你的回答。它幫助我走上正軌。 – MountainX

相關問題