[Checkins] SVN: zope.password/trunk/ Remove the completely useless 'cosmetic' salt from the MD5 manager.

Martijn Pieters mj at zopatista.com
Sun Feb 20 10:05:06 EST 2011


Log message for revision 120466:
  Remove the completely useless 'cosmetic' salt from the MD5 manager.
  
  The generated salt was not being used to generate the actual hash and had no
  cryptographic meaning. It only served to make the output incompatible with
  RFC 2307 MD5 implementations. Any encoded input with the salt still in place are still supported for password checks.

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 14:38:07 UTC (rev 120465)
+++ zope.password/trunk/CHANGES.txt	2011-02-20 15:05:06 UTC (rev 120466)
@@ -19,6 +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.
+
 3.6.1 (2010-05-27)
 ------------------
 

Modified: zope.password/trunk/README.txt
===================================================================
--- zope.password/trunk/README.txt	2011-02-20 14:38:07 UTC (rev 120465)
+++ zope.password/trunk/README.txt	2011-02-20 15:05:06 UTC (rev 120466)
@@ -13,10 +13,7 @@
   more secure implementations.
 
 * MD5PasswordManager - a password manager that uses MD5 algorithm to
-  encode passwords. It adds salt to the encoded password, but the salt
-  is not used for encoding the password itself, so the use of salt in
-  it is purely cosmetic. It's generally weak against dictionary
-  attacks.
+  encode passwords. It's generally weak against dictionary attacks.
  
 * SHA1PasswordManager - a password manager that uses SHA1 algorithm to
   encode passwords. It has the same salt weakness as the

Modified: zope.password/trunk/src/zope/password/password.py
===================================================================
--- zope.password/trunk/src/zope/password/password.py	2011-02-20 14:38:07 UTC (rev 120465)
+++ zope.password/trunk/src/zope/password/password.py	2011-02-20 15:05:06 UTC (rev 120466)
@@ -168,9 +168,6 @@
 class MD5PasswordManager(PlainTextPasswordManager):
     """MD5 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 = MD5PasswordManager()
@@ -178,7 +175,7 @@
     True
 
     >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
-    >>> encoded = manager.encodePassword(password, salt="")
+    >>> encoded = manager.encodePassword(password)
     >>> encoded
     '{MD5}86dddccec45db4599f1ac00018e54139'
     >>> manager.match(encoded)
@@ -189,8 +186,8 @@
     False
 
     >>> encoded = manager.encodePassword(password)
-    >>> encoded[-32:]
-    '86dddccec45db4599f1ac00018e54139'
+    >>> encoded
+    '{MD5}86dddccec45db4599f1ac00018e54139'
     >>> manager.match(encoded)
     True
     >>> manager.checkPassword(encoded, password)
@@ -198,13 +195,10 @@
     >>> 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 {MD5} 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
     '86dddccec45db4599f1ac00018e54139'
@@ -218,19 +212,23 @@
     >>> 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 32 bytes
+    of the pre-existing hash are used:
+    
+    >>> manager.checkPassword('salt' + encoded, password)
+    True
+
     """
 
     def encodePassword(self, password, salt=None):
-        if salt is None:
-            salt = "%08x" % randint(0, 0xffffffff)
-        return '{MD5}%s%s' % (salt, md5(_encoder(password)[0]).hexdigest())
+        # The salt argument only exists for backwards compatibility and is
+        # ignored on purpose.
+        return '{MD5}%s' % (md5(_encoder(password)[0]).hexdigest())
 
     def checkPassword(self, encoded_password, password):
-        if encoded_password.startswith('{MD5}'):
-            salt = encoded_password[5:-32]
-            return encoded_password == self.encodePassword(password, salt)
-        salt = encoded_password[:-32]
-        return encoded_password == self.encodePassword(password, salt)[5:]
+        return encoded_password[-32:] == self.encodePassword(password)[-32:]
 
     def match(self, encoded_password):
         return encoded_password.startswith('{MD5}')



More information about the checkins mailing list