[Zope-dev] Salt-weakness in zope.app.authentication passwordmanagers?
Uli Fouquet
uli at gnufix.de
Sat Jan 17 12:01:34 EST 2009
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Dies ist ein digital signierter Nachrichtenteil
Url : http://mail.zope.org/pipermail/zope-dev/attachments/20090117/0e712892/attachment.bin
More information about the Zope-Dev
mailing list