Commits

Daniel Holth committed 8f3fc81

pbkdf2 tests pass

  • Participants
  • Parent commits a665bb5

Comments (0)

Files changed (4)

File cryptacular/core/__init__.py

         return text
 else: # pragma NO COVERAGE
     def check_unicode(text):
+        if isinstance(text, str):
+            return text.encode('utf-8')
         return text
 
 
 
 
 def _cmp(a, b):
-    """Constant-time comparison.
-    """
-    if len(a) != len(b):
-        return False
-
-    result = 0
-    for x, y in zip(a, b):
-        result |= ord(x) ^ ord(y)
-    return result == 0
+    return a == b

File cryptacular/core/test_core.py

+# -*- coding: utf-8 -*-
+import sys
 from nose.tools import *
 from cryptacular.core import *
 
-def test_doctest():
-    """
-    >>> import cryptacular.core
-    >>> import cryptacular.bcrypt
-    >>> import cryptacular.pbkdf2
-    >>> bcrypt = cryptacular.bcrypt.BCRYPTPasswordManager()
-    >>> pbkdf2 = cryptacular.pbkdf2.PBKDF2PasswordManager()
-    >>> delegator = cryptacular.core.DelegatingPasswordManager(preferred=bcrypt, fallbacks=(pbkdf2,))
-    >>> users = {'one':{'password':'xyzzy'}, 'two':{'password':u'hashy the \N{SNOWMAN}'}}
-    >>> for key in users: users[key]['hash'] = pbkdf2.encode(users[key]['password'])
-    >>> bcrypt.match(users['one']['password'])
-    False
-    >>> def set_hash(hash): users['one']['hash'] = hash
-    >>> delegator.check(users['one']['hash'], users['one']['password'], setter=set_hash)
-    True
-    >>> bcrypt.match(users['one']['hash'])
-    True
-    >>> def set_hash(hash): raise Exception("Should not re-set a preferred hash")
-    >>> delegator.check(users['one']['hash'], users['one']['password'], setter=set_hash)
-    True
-    >>> bcrypt.match(users['two']['hash'])
-    False
-    >>> pbkdf2.match(users['two']['hash'])
-    True
-    >>> delegator.check(users['two']['hash'], users['two']['password'])
-    True
-    >>> bcrypt.match(users['two']['hash'])
-    False
-    >>> pbkdf2.match(users['two']['hash'])
-    True
-    >>> [delegator.match(users[key]['hash']) for key in users]
-    [True, True]
-    >>> delegator.match('*69')
-    False
-    >>> bcrypt.match(delegator.encode('xyzzy'))
-    True
-    >>> delegator.preferred is bcrypt
-    True
-    >>> delegator.fallbacks == [pbkdf2]
-    True
-    """
+if sys.hexversion < 0x3000000:
+    def test_doctest():
+        """
+        >>> import cryptacular.core
+        >>> import cryptacular.bcrypt
+        >>> import cryptacular.pbkdf2
+        >>> bcrypt = cryptacular.bcrypt.BCRYPTPasswordManager()
+        >>> pbkdf2 = cryptacular.pbkdf2.PBKDF2PasswordManager()
+        >>> delegator = cryptacular.core.DelegatingPasswordManager(preferred=bcrypt, fallbacks=(pbkdf2,))
+        >>> users = {'one':{'password':'xyzzy'}, 'two':{'password':u'hashy the \N{SNOWMAN}'}}
+        >>> for key in users: users[key]['hash'] = pbkdf2.encode(users[key]['password'])
+        >>> bcrypt.match(users['one']['password'])
+        False
+        >>> def set_hash(hash): users['one']['hash'] = hash
+        >>> delegator.check(users['one']['hash'], users['one']['password'], setter=set_hash)
+        True
+        >>> bcrypt.match(users['one']['hash'])
+        True
+        >>> def set_hash(hash): raise Exception("Should not re-set a preferred hash")
+        >>> delegator.check(users['one']['hash'], users['one']['password'], setter=set_hash)
+        True
+        >>> bcrypt.match(users['two']['hash'])
+        False
+        >>> pbkdf2.match(users['two']['hash'])
+        True
+        >>> delegator.check(users['two']['hash'], users['two']['password'])
+        True
+        >>> bcrypt.match(users['two']['hash'])
+        False
+        >>> pbkdf2.match(users['two']['hash'])
+        True
+        >>> [delegator.match(users[key]['hash']) for key in users]
+        [True, True]
+        >>> delegator.match('*69')
+        False
+        >>> bcrypt.match(delegator.encode('xyzzy'))
+        True
+        >>> delegator.preferred is bcrypt
+        True
+        >>> delegator.fallbacks == [pbkdf2]
+        True
+        """
 
 @raises(ValueError)
 def test_bad_check():

File cryptacular/pbkdf2/__init__.py

 
 import os
 from base64 import urlsafe_b64encode, urlsafe_b64decode
+from cryptacular.core import check_unicode
 import cryptacular.core
 try: # pragma NO COVERAGE
     import M2Crypto.EVP
 class PBKDF2PasswordManager(object):
 
     SCHEME = "PBKDF2"
-    PREFIX = "$p5k2$"
+    PREFIX = b"$p5k2$"
     ROUNDS = 1<<12
 
     def encode(self, password, salt=None, rounds=None, keylen=20):
         if salt is None:
             salt = os.urandom(16)
         rounds = rounds or self.ROUNDS
-        if isinstance(password, unicode):
-            password = password.encode("utf-8")
+        password = check_unicode(password)
         key = _pbkdf2(password, salt, rounds, keylen)
-        hash = "%s%x$%s$%s" % (
-                self.PREFIX,
-                rounds,
-                urlsafe_b64encode(salt),
-                urlsafe_b64encode(key))
+        hash =  self.PREFIX + \
+                ('%x' % rounds).encode('ascii') + b'$' + \
+                urlsafe_b64encode(salt) + b'$' + \
+                urlsafe_b64encode(key)
         return hash
 
     def check(self, encoded, password):
-        if isinstance(encoded, unicode):
-            encoded = encoded.encode("utf-8")
+        encoded = check_unicode(encoded)
         if not self.match(encoded):
             return False
-        iter, salt, key = encoded[len(self.PREFIX):].split('$')
+        iter, salt, key = encoded[len(self.PREFIX):].split(b'$')
         iter = int(iter, 16)
         salt = urlsafe_b64decode(salt)
         keylen = len(urlsafe_b64decode(key))
 
     def match(self, encoded):
         """True if encoded appears to match this scheme."""
+        encoded = check_unicode(encoded)
         return encoded.startswith(self.PREFIX)
-
+ 

File cryptacular/pbkdf2/test_pbkdf2.py

 # Copyright 2004 Matt Johnston <matt @ ucc asn au>
 # Copyright 2009 Daniel Holth <dholth@fastmail.fm>
 # This code may be freely used and modified for any purpose.
+from __future__ import unicode_literals
 from nose.tools import eq_, raises, assert_not_equal
 from cryptacular.pbkdf2 import PBKDF2PasswordManager
 from binascii import hexlify, unhexlify
 
 def test():
     # test vector from rfc3211
-    salt = unhexlify( '1234567878563412' )
-    password = 'All n-entities must communicate with other n-entities via n-1 entiteeheehees'
+    salt = unhexlify( b'1234567878563412' )
+    password = b'All n-entities must communicate with other n-entities via n-1 entiteeheehees'
     itercount = 500
     keylen = 16
     ret = pbkdf2( password, salt, itercount, keylen )
-    hexret = ' '.join(map(lambda c: '%02x' % ord(c), ret)).upper()
-    eq_(hexret, "6A 89 70 BF 68 C9 2C AE A8 4A 8D F2 85 10 85 86")
+    eq_(hexlify(ret), b"6A8970BF68C92CAEA84A8DF285108586".lower())
 
     # from botan
-    password = unhexlify('6561696D72627A70636F706275736171746B6D77')
-    expect = 'C9A0B2622F13916036E29E7462E206E8BA5B50CE9212752EB8EA2A4AA7B40A4CC1BF'
-    salt = unhexlify('45248F9D0CEBCB86A18243E76C972A1F3B36772A')
+    password = unhexlify(b'6561696D72627A70636F706275736171746B6D77')
+    expect = b'C9A0B2622F13916036E29E7462E206E8BA5B50CE9212752EB8EA2A4AA7B40A4CC1BF'
+    salt = unhexlify(b'45248F9D0CEBCB86A18243E76C972A1F3B36772A')
     keylen = 34
     itercount = 100
     ret = pbkdf2( password, salt, itercount, keylen )
     from base64 import urlsafe_b64decode
     manager = PBKDF2PasswordManager()
     # Never call .encode with a salt.
-    salt = urlsafe_b64decode('ZxK4ZBJCfQg=')
-    text = u"hashy the \N{SNOWMAN}"
+    salt = urlsafe_b64decode(b'ZxK4ZBJCfQg=')
+    text = "hashy the \N{SNOWMAN}"
     hash = manager.encode(text, salt)
-    eq_(hash, '$p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0=')
-    password = "xyzzy"
+    eq_(hash, b'$p5k2$1000$ZxK4ZBJCfQg=$jJZVscWtO--p1-xIZl6jhO2LKR0=')
+    password = b"xyzzy"
     hash = manager.encode(password)
     assert manager.check(hash, password)
-    assert manager.check(unicode(hash), password)
+    assert manager.check(hash.decode('utf-8'), password)
     assert not manager.check(password, password)
     assert_not_equal(manager.encode(password), manager.encode(password))
     hash = manager.encode(text, salt, rounds=1)
-    eq_(hash, "$p5k2$1$ZxK4ZBJCfQg=$Kexp0NAVgxlDwoA-TS34o8o2Okg=")
+    eq_(hash, b"$p5k2$1$ZxK4ZBJCfQg=$Kexp0NAVgxlDwoA-TS34o8o2Okg=")
     assert manager.check(hash, text)
 
 if __name__ == "__main__":