Use byte type for passwords hash encoding
authorJeremy Stanley <fungi@yuggoth.org>
Tue, 23 Apr 2013 17:39:49 +0000 (17:39 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Tue, 23 Apr 2013 17:39:49 +0000 (17:39 +0000)
* lib/mudpy/password.py: Raw hash values are manipulated as bytes for
Py3K compatibility.

lib/mudpy/password.py

index 56bdbfe..68e1a5f 100644 (file)
@@ -1,7 +1,7 @@
 # -*- coding: utf-8 -*-
 """Password hashing functions and constants for the mudpy engine."""
 
-# Copyright (c) 2004-2012 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# Copyright (c) 2004-2013 Jeremy Stanley <fungi@yuggoth.org>. Permission
 # to use, copy, modify, and distribute this software is granted under
 # terms provided in the LICENSE file distributed with this software.
 
@@ -21,12 +21,10 @@ def _pack_bytes(numbers):
     between 0 and 255 into a packed sequence akin to a C-style string.
     """
     import struct
-    # this will need to be declared as b"" during 2to3 migration
-    packed = ""
+    packed = b""
     for number in numbers:
         number = int(number)
         assert 0 <= number <= 255
-        # need to use b"B" during 2to3 migration
         packed += struct.pack("B", number)
     return packed
 
@@ -39,8 +37,8 @@ def _bytes_to_text(byte_sequence):
     import base64
     return base64.b64encode(
         byte_sequence,
-        "./".encode("ascii")
-    ).rstrip("=")
+        b"./"
+    ).decode("ascii").rstrip("=")
 
 
 def _generate_salt(salt_len=2):
@@ -71,11 +69,10 @@ def upgrade_legacy_hash(legacy_hash, salt, sep="$"):
     import re
     assert re.match("^[0-9a-f]{32}$",
                     legacy_hash), "Not a valid MD5 hexdigest"
-    # this needs to be declared as b"" in 2to3
-    collapsed = ""
+    collapsed = b""
     for i in range(16):
         # this needs to become a byte() call in 2to3
-        collapsed += chr(int(legacy_hash[2 * i:2 * i + 2], 16))
+        collapsed += bytes(legacy_hash[2 * i:2 * i + 2].decode("ascii"))
     return "%s%s%s%s%s%s%s%s" % (
         sep,
         MD5,
@@ -164,11 +161,17 @@ def create(
     # iterate the hashing algorithm over its own digest the specified
     # number of times
     for i in range(2 ** rounds):
-        hashed = algorithms[algorithm](hashed).digest()
+        hashed = algorithms[algorithm](hashed.encode("utf-8")).digest()
+        # TODO: remove this exception trap after the switch to py2k
+        try:
+            hashed = "".join(format(x, "02x") for x in bytes(hashed))
+        except ValueError:
+            hashed = "".join(format(ord(x), "02x") for x in bytes(hashed))
 
     # concatenate the output fields, coercing into text form as needed
     return "%s%s%s%s%s%s%s%s" % (
-        sep, algorithm, sep, rounds, sep, salt, sep, _bytes_to_text(hashed)
+        sep, algorithm, sep, rounds, sep, salt, sep,
+        _bytes_to_text(hashed.encode("ascii"))
     )