[Checkins] SVN: zope.password/trunk/ Remove the 'cosmetic' salt from the SHA1 implementation as well, update docs.

Martijn Pieters mj at zopatista.com
Sun Feb 20 10:14:41 EST 2011


Log message for revision 120468:
  Remove the 'cosmetic' salt from the SHA1 implementation as well, update docs.

Changed:
  U   zope.password/trunk/CHANGES.txt
  U   zope.password/trunk/README.txt
  U   zope.password/trunk/src/zope/password/password.py

-=-
Modified: zope.password/trunk/CHANGES.txt
===================================================================
--- zope.password/trunk/CHANGES.txt	2011-02-20 15:07:25 UTC (rev 120467)
+++ zope.password/trunk/CHANGES.txt	2011-02-20 15:14:41 UTC (rev 120468)
@@ -19,10 +19,11 @@
 - Add a MySQL PASSWORD() (versions before 4.1) password manager, as also found
   in Zope2's AccessControl.AuthEncoding module.
 
-- Remove the useless, cosmetic salt from the MD5 password manager. This makes
-  this manager compatible with other MD5 hash implementations such as RFC 2307
-  but doesn't lower it's security in any way. Old, still 'salted' password
-  hashes are still supported.
+- Remove the useless, cosmetic salt from the MD5 and SHA1 password managers.
+  This makes the output of these managers compatible with other MD5 and SHA1
+  hash implementations such as RFC 2307 but doesn't lower it's security in any
+  way. Checking passwards against old, still 'salted' password hashes is still
+  supported.
 
 3.6.1 (2010-05-27)
 ------------------

Modified: zope.password/trunk/README.txt
===================================================================
--- zope.password/trunk/README.txt	2011-02-20 15:07:25 UTC (rev 120467)
+++ zope.password/trunk/README.txt	2011-02-20 15:14:41 UTC (rev 120468)
@@ -13,11 +13,11 @@
   more secure implementations.
 
 * MD5PasswordManager - a password manager that uses MD5 algorithm to
-  encode passwords. It's generally weak against dictionary attacks.
+  encode passwords. It's generally weak against dictionary attacks due to a
+  lack of a salt.
  
 * SHA1PasswordManager - a password manager that uses SHA1 algorithm to
-  encode passwords. It has the same salt weakness as the
-  MD5PasswordManager.
+  encode passwords. It has the same weakness as the MD5PasswordManager.
  
 * SSHAPasswordManager - the most secure password manager that is
   strong against dictionary attacks. It's basically SHA1-encoding

Modified: zope.password/trunk/src/zope/password/password.py
===================================================================
--- zope.password/trunk/src/zope/password/password.py	2011-02-20 15:07:25 UTC (rev 120467)
+++ zope.password/trunk/src/zope/password/password.py	2011-02-20 15:14:41 UTC (rev 120468)
@@ -18,7 +18,6 @@
 from base64 import urlsafe_b64encode
 from base64 import urlsafe_b64decode
 from os import urandom
-from random import randint
 from codecs import getencoder
 try:
     from hashlib import md5, sha1
@@ -227,9 +226,6 @@
 class SHA1PasswordManager(PlainTextPasswordManager):
     """SHA1 password manager.
 
-    Note: use of salt in this password manager is purely
-    cosmetical. Use SSHA if you want increased security.
-
     >>> from zope.interface.verify import verifyObject
 
     >>> manager = SHA1PasswordManager()
@@ -237,7 +233,7 @@
     True
 
     >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
-    >>> encoded = manager.encodePassword(password, salt="")
+    >>> encoded = manager.encodePassword(password)
     >>> encoded
     '{SHA}04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
     >>> manager.match(encoded)
@@ -247,23 +243,10 @@
     >>> manager.checkPassword(encoded, password + u"wrong")
     False
 
-    >>> encoded = manager.encodePassword(password)
-    >>> encoded[-40:]
-    '04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
-    >>> manager.match(encoded)
-    True
-    >>> manager.checkPassword(encoded, password)
-    True
-    >>> manager.checkPassword(encoded, password + u"wrong")
-    False
-
-    >>> manager.encodePassword(password) != manager.encodePassword(password)
-    True
-
     The old version of this password manager didn't add the {SHA} to
     passwords. Let's check if it can work with old stored passwords.
 
-    >>> encoded = manager.encodePassword(password, salt="")
+    >>> encoded = manager.encodePassword(password)
     >>> encoded = encoded[5:]
     >>> encoded
     '04b4eec7154c5f3a2ec6d2956fb80b80dc737402'
@@ -277,6 +260,14 @@
     >>> manager.match(encoded)
     False
 
+    A previous version of this manager also created a cosmetic salt, added
+    to the start of the hash, but otherwise not used in creating the hash
+    itself. To still support these 'hashed' passwords, only the last 40 bytes
+    of the pre-existing hash are used:
+    
+    >>> manager.checkPassword('salt' + encoded, password)
+    True
+
     Previously, this password manager used {SHA1} as a prefix, but this was
     changed to be compatible with LDAP (RFC 2307). The old prefix is still
     supported:
@@ -293,17 +284,15 @@
     """
 
     def encodePassword(self, password, salt=None):
-        if salt is None:
-            salt = "%08x" % randint(0, 0xffffffff)
-        return '{SHA}%s%s' % (salt, sha1(_encoder(password)[0]).hexdigest())
+        # The salt argument only exists for backwards compatibility and is
+        # ignored on purpose.
+        return '{SHA}%s' % sha1(_encoder(password)[0]).hexdigest()
 
     def checkPassword(self, encoded_password, password):
         if self.match(encoded_password):
             encoded = encoded_password[encoded_password.find('}') + 1:]
-            salt = encoded[:-40]
-            return encoded == self.encodePassword(password, salt)[5:]
-        salt = encoded_password[:-40]
-        return encoded_password == self.encodePassword(password, salt)[5:]
+            return encoded[-40:] == self.encodePassword(password)[5:]
+        return encoded_password[-40:] == self.encodePassword(password)[5:]
 
     def match(self, encoded_password):
         return (



More information about the checkins mailing list