[Checkins] SVN: zope.password/trunk/ Port AccessControl.AuthEncoding.MySQLDigestScheme to zope.password.

Martijn Pieters mj at zopatista.com
Sun Feb 20 08:59:02 EST 2011


Log message for revision 120462:
  Port AccessControl.AuthEncoding.MySQLDigestScheme to zope.password.
  
  This is very much a legacy scheme, encoding to a very weak 16 bit hash with no salt support.

Changed:
  U   zope.password/trunk/CHANGES.txt
  U   zope.password/trunk/src/zope/password/configure.zcml
  U   zope.password/trunk/src/zope/password/legacy.py
  U   zope.password/trunk/src/zope/password/testing.py

-=-
Modified: zope.password/trunk/CHANGES.txt
===================================================================
--- zope.password/trunk/CHANGES.txt	2011-02-20 13:37:08 UTC (rev 120461)
+++ zope.password/trunk/CHANGES.txt	2011-02-20 13:59:02 UTC (rev 120462)
@@ -15,6 +15,9 @@
 - Add a crypt password manager to fully support all methods named in RFC 2307.
   It is contained in the 'legacy' module however, to flag crypt's status.
 
+- Add a MySQL PASSWORD() (versions before 4.1) password manager, as also found
+  in Zope2's AccessControl.AuthEncoding module.
+
 3.6.1 (2010-05-27)
 ------------------
 

Modified: zope.password/trunk/src/zope/password/configure.zcml
===================================================================
--- zope.password/trunk/src/zope/password/configure.zcml	2011-02-20 13:37:08 UTC (rev 120461)
+++ zope.password/trunk/src/zope/password/configure.zcml	2011-02-20 13:59:02 UTC (rev 120462)
@@ -27,6 +27,12 @@
       factory=".password.SSHAPasswordManager"
       />
 
+  <utility
+      name="MYSQL"
+      provides=".interfaces.IPasswordManager"
+      factory=".legacy.MySQLPasswordManager"
+      />
+
   <configure zcml:condition="installed crypt">
   <utility
       name="Crypt"

Modified: zope.password/trunk/src/zope/password/legacy.py
===================================================================
--- zope.password/trunk/src/zope/password/legacy.py	2011-02-20 13:37:08 UTC (rev 120461)
+++ zope.password/trunk/src/zope/password/legacy.py	2011-02-20 13:59:02 UTC (rev 120462)
@@ -112,3 +112,73 @@
         def match(self, encoded_password):
             return encoded_password.startswith('{CRYPT}')
 
+class MySQLPasswordManager(object):
+    """A MySQL digest manager.
+
+    This Password Manager implements the digest scheme as implemented in the
+    MySQL PASSWORD function in MySQL versions before 4.1. Note that this
+    method results in a very weak 16-byte hash.
+
+    >>> from zope.interface.verify import verifyObject
+
+    >>> manager = MySQLPasswordManager()
+    >>> verifyObject(IPasswordManager, manager)
+    True
+
+    >>> password = u"right \N{CYRILLIC CAPITAL LETTER A}"
+    >>> encoded = manager.encodePassword(password)
+    >>> encoded
+    '{MYSQL}0ecd752c5097d395'
+    >>> manager.match(encoded)
+    True
+    >>> manager.checkPassword(encoded, password)
+    True
+    >>> manager.checkPassword(encoded, password + u"wrong")
+    False
+
+    Using the password 'PHP & Information Security' should result in the
+    hash ``379693e271cd3bd6``, according to 
+    http://phpsec.org/articles/2005/password-hashing.html
+
+    Our password manager generates the same value when seeded with the, so we 
+    can be sure, our output is compatible with MySQL versions before 4.1::
+
+    >>> password = 'PHP & Information Security'
+    >>> encoded = manager.encodePassword(password)
+    >>> encoded
+    '{MYSQL}379693e271cd3bd6'
+
+    >>> manager.checkPassword(encoded, password)
+    True
+    >>> manager.checkPassword(encoded, password + u"wrong")
+    False
+
+    The manager only claims to implement MYSQL encodings, anything not 
+    starting with the string {MYSQL} returns False::
+
+    >>> manager.match('{MD5}someotherhash')
+    False
+
+    """
+
+    implements(IPasswordManager)
+
+    def encodePassword(self, password):
+        nr = 1345345333L
+        add = 7
+        nr2 = 0x12345671L
+        for i in _encoder(password)[0]:
+            if i == ' ' or i == '\t':
+                continue
+            nr ^= (((nr & 63) + add) * ord(i)) + (nr << 8)
+            nr2 += (nr2 << 8) ^ nr
+            add += ord(i)
+        r0 = nr & ((1L << 31) - 1L)
+        r1 = nr2 & ((1L << 31) - 1L)
+        return "{MYSQL}%08lx%08lx" % (r0, r1)
+
+    def checkPassword(self, encoded_password, password):
+        return encoded_password == self.encodePassword(password)
+
+    def match(self, encoded_password):
+        return encoded_password.startswith('{MYSQL}')

Modified: zope.password/trunk/src/zope/password/testing.py
===================================================================
--- zope.password/trunk/src/zope/password/testing.py	2011-02-20 13:37:08 UTC (rev 120461)
+++ zope.password/trunk/src/zope/password/testing.py	2011-02-20 13:59:02 UTC (rev 120462)
@@ -23,6 +23,7 @@
 from zope.password.password import MD5PasswordManager
 from zope.password.password import SHA1PasswordManager
 from zope.password.password import SSHAPasswordManager
+from zope.password.legacy import MySQLPasswordManager
 from zope.password.vocabulary import PasswordManagerNamesVocabulary
 
 try:
@@ -45,6 +46,8 @@
     <zope.password.password.MD5PasswordManager object at 0x...>
     >>> getUtility(IPasswordManager, 'SHA1')
     <zope.password.password.SHA1PasswordManager object at 0x...>
+    >>> getUtility(IPasswordManager, 'MYSQL')
+    <zope.password.legacy.MySQLPasswordManager object at 0x...>
 
     >>> try:
     ...     import crypt
@@ -68,6 +71,8 @@
     True
     >>> 'MD5' in voc
     True
+    >>> 'MYSQL' in voc
+    True
 
     >>> CryptPasswordManager is None or 'Crypt' in voc
     True
@@ -77,6 +82,7 @@
     provideUtility(SSHAPasswordManager(), IPasswordManager, 'SSHA')
     provideUtility(MD5PasswordManager(), IPasswordManager, 'MD5')
     provideUtility(SHA1PasswordManager(), IPasswordManager, 'SHA1')
+    provideUtility(MySQLPasswordManager(), IPasswordManager, 'MYSQL')
     
     if CryptPasswordManager is not None:
         provideUtility(CryptPasswordManager, IPasswordManager, 'Crypt')



More information about the checkins mailing list