diff options
| author | Eli Collins <elic@assurancetechnologies.com> | 2011-06-17 00:17:40 -0400 |
|---|---|---|
| committer | Eli Collins <elic@assurancetechnologies.com> | 2011-06-17 00:17:40 -0400 |
| commit | 3f7c43556e647df2b2993fc4cf47a87933e276cc (patch) | |
| tree | 03c9005da2e56c7fe02b1cde674ff10f95541304 | |
| parent | 96e8745f3673c99a31e03b30a75825a934b22507 (diff) | |
| download | passlib-3f7c43556e647df2b2993fc4cf47a87933e276cc.tar.gz | |
utils.des now py3 compat; fixed some other utils as well
| -rw-r--r-- | passlib/tests/test_utils.py | 6 | ||||
| -rw-r--r-- | passlib/utils/__init__.py | 23 | ||||
| -rw-r--r-- | passlib/utils/des.py | 31 |
3 files changed, 40 insertions, 20 deletions
diff --git a/passlib/tests/test_utils.py b/passlib/tests/test_utils.py index bed90aa..e43b181 100644 --- a/passlib/tests/test_utils.py +++ b/passlib/tests/test_utils.py @@ -96,7 +96,7 @@ class DesTest(TestCase): test_des_vectors = [ (line[4:20], line[21:37], line[38:54]) for line in - """ 0000000000000000 0000000000000000 8CA64DE9C1B123A7 +b(""" 0000000000000000 0000000000000000 8CA64DE9C1B123A7 FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF 7359B2163E4EDC58 3000000000000000 1000000000000001 958E6E627A05557B 1111111111111111 1111111111111111 F40379AB9E0EC533 @@ -130,7 +130,7 @@ class DesTest(TestCase): FFFFFFFFFFFFFFFF 0000000000000000 CAAAAF4DEAF1DBAE 0123456789ABCDEF 0000000000000000 D5D44FF720683D0D FEDCBA9876543210 FFFFFFFFFFFFFFFF 2A2BB008DF97C2F2 - """.split("\n") if line.strip() + """).split(b("\n")) if line.strip() ] def test_des_encrypt_block(self): @@ -143,7 +143,7 @@ class DesTest(TestCase): #test 7 byte key #FIXME: use a better key - k,p,c = '00000000000000', 'FFFFFFFFFFFFFFFF', '355550B2150E2451' + k,p,c = b('00000000000000'), b('FFFFFFFFFFFFFFFF'), b('355550B2150E2451') k = unhexlify(k) p = unhexlify(p) c = unhexlify(c) diff --git a/passlib/utils/__init__.py b/passlib/utils/__init__.py index fa37035..bebf7a8 100644 --- a/passlib/utils/__init__.py +++ b/passlib/utils/__init__.py @@ -372,13 +372,20 @@ bord = ord # end Py2k # def bchrs(*values): - "takes series of ints, returns bytes" + "takes series of ints, returns bytes; like chr() but for bytes, and w/ multi args" # Py2k # return bjoin(chr(v) for v in values) # Py3k # #return bytes(values) # end Py3k # +# Py2k # +def bjoin_ints(values): + return bjoin(chr(v) for v in values) +# Py3k # +#bjoin_ints = bytes +# end Py3k # + #================================================================================= #numeric helpers #================================================================================= @@ -422,21 +429,25 @@ def bytes_to_int(value): "decode string of bytes as single big-endian integer" out = 0 for v in value: - out = (out<<8) | ord(v) + out = (out<<8) | bord(v) return out def int_to_bytes(value, count): "encodes integer into single big-endian byte string" assert value < (1<<(8*count)), "value too large for %d bytes: %d" % (count, value) - return ''.join( - chr((value>>s) & 0xff) + return bjoin_ints( + ((value>>s) & 0xff) for s in xrange(8*count-8,-8,-8) ) -_join = "".join def xor_bytes(left, right): "perform bitwise-xor of two byte-strings" - return _join(chr(ord(l) ^ ord(r)) for l, r in zip(left, right)) + #NOTE: this could use bjoin_ints(), but speed is *really* important here (c.f. PBKDF2) + # Py2k # + return bjoin(chr(ord(l) ^ ord(r)) for l, r in zip(left, right)) + # Py3k # + #return bytes(l ^ r for l, r in zip(left, right)) + # end Py3k # #================================================================================= #alt base64 encoding diff --git a/passlib/utils/des.py b/passlib/utils/des.py index 279c638..88b591d 100644 --- a/passlib/utils/des.py +++ b/passlib/utils/des.py @@ -43,7 +43,7 @@ which has some nice notes on how this all works - #imports #========================================================= #pkg -from passlib.utils import bytes_to_int, int_to_bytes +from passlib.utils import bytes_to_int, int_to_bytes, bytes, bord, bjoin_ints #local __all__ = [ "expand_des_key", @@ -571,45 +571,54 @@ def permute(c, p): #========================================================= #des frontend #========================================================= -def expand_des_key(source): +def expand_des_key(key): "convert 7 byte des key to 8 byte des key (by adding parity bit every 7 bits)" + if not isinstance(key, bytes): + raise TypeError("key must be bytes, not %s" % (type(key),)) + #NOTE: could probably do this much more cleverly and efficiently, # but no need really given it's use. #NOTE: the parity bits are generally ignored, including by des_encrypt_block below - assert len(source) == 7 + assert len(key) == 7 def iter_bits(source): for c in source: - v = ord(c) + v = bord(c) for i in xrange(7,-1,-1): yield (v>>i) & 1 out = 0 p = 1 - for i, b in enumerate(iter_bits(source)): + for i, b in enumerate(iter_bits(key)): out = (out<<1) + b p ^= b if i % 7 == 6: out = (out<<1) + p p = 1 - return ''.join( - chr((out>>s) & 0xFF) + return bjoin_ints( + ((out>>s) & 0xFF) for s in xrange(8*7,-8,-8) ) def des_encrypt_block(key, input): """do traditional encryption of a single DES block - :arg key: 8 byte des key string - :arg input: 8 byte plaintext string - :returns: 8 byte ciphertext string + :arg key: 8 byte des key + :arg input: 8 byte plaintext + :returns: 8 byte ciphertext + + all values must be :class:`bytes` """ - assert len(input) == 8 + if not isinstance(key, bytes): + raise TypeError("key must be bytes, not %s" % (type(key),)) if len(key) == 7: key = expand_des_key(key) assert len(key) == 8 + if not isinstance(input, bytes): + raise TypeError("input must be bytes, not %s" % (type(input),)) + assert len(input) == 8 input = bytes_to_int(input) key = bytes_to_int(key) out = mdes_encrypt_int_block(key, input, 0, 1) |
