Pbkdf2_sha256 加密

Pbkdf2_sha256 encryption

大家好,我正在研究 Pbkdf2_sha256 的工作原理。

这是我目前正在研究的一些破解哈希

PBKDF2 pbkdf2_sha256000[=11=]5OtPxTXhPq$K/2GplWPJsBVj+qbgdKW8YEteQyUkIiquT5MaOhPo4Y=:harry
PBKDF2 pbkdf2_sha256000[=11=]Qhibr5Mbeg$l9grYueDrl3qN3NA7e9j5PodgV1XkGTz0Z6ajhF99AY=:radio
PBKDF2 pbkdf2_sha256000[=11=]h7h0g1ZKE1$YEobSm/y+cFg/VXhU4gGYJ6eOkZ68jhJ5axDu68Dack=:momo
PBKDF2 pbkdf2_sha256000JMkfGk1RXh$vD+GGZshw5kExtZOpl5+Lht3xECULdbNVOesoTicxto=:fred
PBKDF2 pbkdf2_sha256000vkw1viCg4Jhjlbq10Jh/Su3yqjKfYCnCSt1WlKcKJtsqDET618M0=:get
PBKDF2 pbkdf2_sha256000wayF5JLVSZ/9COWqb6SZG/raqabtU8fNBzkrt2puN7SaKw0U7jBs=:987456321

这是我计算散列的代码和输出

>>> from passlib.hash import pbkdf2_sha256
>>> from passlib.utils.binary import ab64_decode
>>> print(pbkdf2_sha256.hash("harry", rounds=10000, salt=ab64_decode(b'005OtPxTXhPq')))
$pbkdf2-sha256000[=12=]5OtPxTXhPq$l9LhRMPBW.EEdlBE9b.P0Z70Kxidl9EJhfGK7FiLUHA

比较这两者,你会发现不同之处。

$pbkdf2_sha256000[=13=]5OtPxTXhPq$K/2GplWPJsBVj+qbgdKW8YEteQyUkIiquT5MaOhPo4Y=
$pbkdf2-sha256000[=13=]5OtPxTXhPq$l9LhRMPBW.EEdlBE9b.P0Z70Kxidl9EJhfGK7FiLUHA

谁能解释一下是什么原因造成的,我该如何计算正确的哈希值?

提前致谢!

正如评论中已经提到的,发布的数据格式不同于passlibpasslib格式已解释here. Salt and hash (checksum) are Base64 encoded. A special Base64 variant is used that is explained here:省略填充 (=) 和空格,应用 . 代替 +.

另一方面,已发布数据的散列是标准的 Base64 编码(即使用 + 而不是 .)和填充 (=)。 此外,盐是 UTF8 解码的。

如果考虑到这一点,则盐和散列是相同的。以下代码从posted数据中判断出passlib数据,并比较salt和hash,其中posted数据的salt和hash以passlib格式显示(即使用 passlib Base64 变体和 Base64 编码盐):

from passlib.hash import pbkdf2_sha256
from base64 import b64decode
from passlib.utils.binary import ab64_encode

def hashAndCompare(crackedHash):
    
    crackedChain = crackedHash.split('$')   
    #crackedChainDigest = crackedChain[0]
    crackedChainRounds = crackedChain[1]
    crackedChainSalt = crackedChain[2]
    crackedChainSaltPasslibFormat = ab64_encode(crackedChainSalt.encode('utf8')).decode('utf8')
    crackedChainHashData = crackedChain[3].split(':')
    crackedChainHash = crackedChainHashData[0]
    crackedChainHashPasslibFormat = ab64_encode(b64decode(crackedChainHash)).decode('utf8')
    crackedChainData = crackedChainHashData[1]
    
    passlibHash = pbkdf2_sha256.hash(crackedChainData, rounds=crackedChainRounds, salt=crackedChainSalt.encode('utf8')) 
    passlibChain = passlibHash.split('$')
    passlibChainSalt = passlibChain[3]
    passlibChainHash = passlibChain[4]
    
    print('Passlib: Hash: {0} Salt: {1}\nCracked: Hash: {2} Salt: {3}\n'.format(passlibChainHash, passlibChainSalt, crackedChainHashPasslibFormat, crackedChainSaltPasslibFormat))

hashAndCompare('pbkdf2_sha256000[=10=]5OtPxTXhPq$K/2GplWPJsBVj+qbgdKW8YEteQyUkIiquT5MaOhPo4Y=:harry')
hashAndCompare('pbkdf2_sha256000[=10=]Qhibr5Mbeg$l9grYueDrl3qN3NA7e9j5PodgV1XkGTz0Z6ajhF99AY=:radio')
hashAndCompare('pbkdf2_sha256000[=10=]h7h0g1ZKE1$YEobSm/y+cFg/VXhU4gGYJ6eOkZ68jhJ5axDu68Dack=:momo')
hashAndCompare('pbkdf2_sha256000JMkfGk1RXh$vD+GGZshw5kExtZOpl5+Lht3xECULdbNVOesoTicxto=:fred')
hashAndCompare('pbkdf2_sha256000vkw1viCg4Jhjlbq10Jh/Su3yqjKfYCnCSt1WlKcKJtsqDET618M0=:get')
hashAndCompare('pbkdf2_sha256000wayF5JLVSZ/9COWqb6SZG/raqabtU8fNBzkrt2puN7SaKw0U7jBs=:987456321')

盐和散列与一致的编码相同:

Passlib: Hash: K/2GplWPJsBVj.qbgdKW8YEteQyUkIiquT5MaOhPo4Y Salt: MDA1T3RQeFRYaFBx
Cracked: Hash: K/2GplWPJsBVj.qbgdKW8YEteQyUkIiquT5MaOhPo4Y Salt: MDA1T3RQeFRYaFBx

Passlib: Hash: l9grYueDrl3qN3NA7e9j5PodgV1XkGTz0Z6ajhF99AY Salt: MDBRaGlicjVNYmVn
Cracked: Hash: l9grYueDrl3qN3NA7e9j5PodgV1XkGTz0Z6ajhF99AY Salt: MDBRaGlicjVNYmVn

Passlib: Hash: YEobSm/y.cFg/VXhU4gGYJ6eOkZ68jhJ5axDu68Dack Salt: MDBoN2gwZzFaS0Ux
Cracked: Hash: YEobSm/y.cFg/VXhU4gGYJ6eOkZ68jhJ5axDu68Dack Salt: MDBoN2gwZzFaS0Ux

Passlib: Hash: vD.GGZshw5kExtZOpl5.Lht3xECULdbNVOesoTicxto Salt: MDFKTWtmR2sxUlho
Cracked: Hash: vD.GGZshw5kExtZOpl5.Lht3xECULdbNVOesoTicxto Salt: MDFKTWtmR2sxUlho

Passlib: Hash: 2hjlbq10Jh/Su3yqjKfYCnCSt1WlKcKJtsqDET618M0 Salt: MDF2a3cxdmlDZzRK
Cracked: Hash: 2hjlbq10Jh/Su3yqjKfYCnCSt1WlKcKJtsqDET618M0 Salt: MDF2a3cxdmlDZzRK

Passlib: Hash: 2/9COWqb6SZG/raqabtU8fNBzkrt2puN7SaKw0U7jBs Salt: MDF3YXlGNUpMVlNa
Cracked: Hash: 2/9COWqb6SZG/raqabtU8fNBzkrt2puN7SaKw0U7jBs Salt: MDF3YXlGNUpMVlNa

Django 使用该格式并且 passlib 具有该格式的函数:Django 1.4 Hashes.

所以,我在 python 的 shell 中做了这个:

>>> from passlib.hash import django_pbkdf2_sha256
>>> secret = 'harry'
>>> hash = 'pbkdf2_sha256000[=10=]5OtPxTXhPq$K/2GplWPJsBVj+qbgdKW8YEteQyUkIiquT5MaOhPo4Y='
>>> django_pbkdf2_sha256.verify(secret, hash)
True
>>> rounds = hash.split('$')[1]
>>> salt = hash.split('$')[2]
>>> django_pbkdf2_sha256.hash(secret, rounds=rounds, salt=salt) == hash
True