Yeah, that's definetely a mistake! The hash needs to be generated
using both salt and password.

Also, I saw a technique when you generate a hash using double hashing,
like this: sha(sha(password) + salt).hexdigest(). It looks even more
secure :)

BTW, to fix it, we need to remember about migration of already stored
hashes. I guess zope.app.generations will do the job.

2009/1/17 Uli Fouquet <u...@gnufix.de>:
> Hi there,
>
> while working on a password manager tool (commandline) for Grok I
> stumbled over the usage of salts in the password managers of
> `zope.app.authentication`.
>
> In short, they seem to generate (and store) a salt number but do not
> make any use of it when it comes to creating the hashes (SHA1, MD5,
> whatever). As a result, same passwords lead always to same hashes, only
> the leading salt number is different. This could be exploited by
> dictionary attacks.
>
> The zope.app.authentication implementation for SHA1-encoding looks
> roughly like this (other hash-encodings have the same problem, if this
> is a valid problem)::
>
>  def encodePassword(password, salt=None):
>    if salt is None:
>      salt = "%08x" % randint(0, 0xffffffff)
>    return salt + sha.new(password).hexdigest()
>
> It looks to me that this way `salt` is only an arbitrary string that
> gets stored in front of the real hash value. The hash value itself will
> not change with the salt.
>
> When I run the following code (`checkPassword` like in
> `zope.app.authentication.password`)::
>
>  def checkPassword(storedPassword, password):
>    salt = storedPassword[:-40]
>    return storedPassword == encodePassword(password, salt)
>
>  for i in range(0,3):
>    enc = encodePassword('asd')
>    print 'Encode "asd"', enc
>    print 'Check: ', checkPassword(enc, 'asd')
>
> I get::
>
>  Encode "asd" 81bde2dbf10e2821bbbea527ea02200352313bc059445190
>  Check:  True
>  Encode "asd" c96cfabdf10e2821bbbea527ea02200352313bc059445190
>  Check:  True
>  Encode "asd" bdba5b69f10e2821bbbea527ea02200352313bc059445190
>  Check:  True
>
> As you can see, only the first eight letters change. And they are
> cleartext part of the encoded password. Not a problem for an
> dictionary-attacker: if one of the hashes in his/her dictionary are
> equal to ``f10e2821bbbea527ea02200352313bc059445190``, then the password
> is cracked. Salts do not improve the security level here, I think.
>
> What I assume to be correct, would be to build the hash from the salt
> plus password (instead of only the password)::
>
>  def encodePassword(password, salt=None):
>    if salt is None:
>      salt = "%08x" % randint(0, 0xffffffff)
>    return salt + sha.new(salt + password).hexdigest()
>
> Using this modified function, I get::
>
>  Encode "asd" 11ac348fe526cc38813fca0e5bd0a59ec3a16686bfa42502
>  Check:  True
>  Encode "asd" 08de8fa19212d743867f8867adee55a9efbe566a8ec56731
>  Check:  True
>  Encode "asd" d454b892224b0cf5b41767acfa80a3732b82c52fc2ee5e9f
>  Check:  True
>
> Now it is harder for an attacker. His dictionary has not only to provide
> the pure hashes for every entry in the dictionary, but also 16**8
> variants for _each_ of the entries. That's it, I think, what salt is
> used for.
>
> As I am not a computer scientist nor a mathematician, I am not sure,
> whether these are valid concerns. But I would like to know, what others
> think about this. Maybe you can correct me here.
>
> Best regards,
>
> --
> Uli
>
>
> _______________________________________________
> Zope-Dev maillist  -  Zope-Dev@zope.org
> http://mail.zope.org/mailman/listinfo/zope-dev
> **  No cross posts or HTML encoding!  **
> (Related lists -
>  http://mail.zope.org/mailman/listinfo/zope-announce
>  http://mail.zope.org/mailman/listinfo/zope )
>
>



-- 
WBR, Dan Korostelev
_______________________________________________
Zope-Dev maillist  -  Zope-Dev@zope.org
http://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 http://mail.zope.org/mailman/listinfo/zope-announce
 http://mail.zope.org/mailman/listinfo/zope )

Reply via email to