PEP 8 conformance for password management library
authorJeremy Stanley <fungi@yuggoth.org>
Fri, 4 Mar 2011 14:41:23 +0000 (14:41 +0000)
committerJeremy Stanley <fungi@yuggoth.org>
Fri, 4 Mar 2011 14:41:23 +0000 (14:41 +0000)
* lib/mudpy/password.py: Conform to the PEP 8 style guide.

lib/mudpy/password.py

index 38bfa82..94d690b 100644 (file)
 # -*- coding: utf-8 -*-
 u"""Password hashing functions and constants for the mudpy engine."""
 
-# Copyright (c) 2004-2010 Jeremy Stanley <fungi@yuggoth.org>. Permission
+# Copyright (c) 2004-2011 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.
 
 # convenience constants for indexing the supported hashing algorithms,
 # guaranteed a stable part of the interface
-MD5 = 0 # hashlib.md5
-SHA1 = 1 # hashlib.sha1
-SHA224 = 2 # hashlib.sha224
-SHA256 = 3 # hashlib.sha256
-SHA384 = 4 # hashlib.sha385
-SHA512 = 5 # hashlib.sha512
+MD5 = 0  # hashlib.md5
+SHA1 = 1  # hashlib.sha1
+SHA224 = 2  # hashlib.sha224
+SHA256 = 3  # hashlib.sha256
+SHA384 = 4  # hashlib.sha385
+SHA512 = 5  # hashlib.sha512
+
 
 def _pack_bytes(numbers):
-   """
-   This is a wrapper around struct.pack, used to turn a list of integers
-   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 = ""
-   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
+    """
+    This is a wrapper around struct.pack, used to turn a list of integers
+    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 = ""
+    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
+
 
 def _bytes_to_text(byte_sequence):
-   """
-   This is a wrapper around base64.b64encode with preferences
-   appropriate for encoding Unix-style passwd hash strings.
-   """
-   import base64
-   return base64.b64encode(
-      byte_sequence,
-      u"./".encode(u"ascii")
-   ).rstrip(u"=")
+    """
+    This is a wrapper around base64.b64encode with preferences
+    appropriate for encoding Unix-style passwd hash strings.
+    """
+    import base64
+    return base64.b64encode(
+        byte_sequence,
+        u"./".encode(u"ascii")
+    ).rstrip(u"=")
+
 
 def _generate_salt(salt_len=2):
-   """
-   This simply generates a sequence of pseudo-random characters (with
-   6-bits of effective entropy per character). Since it relies on base64
-   encoding (which operates on 6-bit chunks of data), we only generate
-   0.75 times as many bytes (rounded up) as the number of characters we
-   need and discard any excess characters over the specified length.
-   This ensures full distribution over each character of the salt.
-   """
-   import math, random
-   salt = []
-   for i in xrange(int(math.ceil(salt_len*0.75))):
-      salt.append( random.randint(0,255) )
-   return _bytes_to_text( _pack_bytes(salt) )[:salt_len]
+    """
+    This simply generates a sequence of pseudo-random characters (with
+    6-bits of effective entropy per character). Since it relies on base64
+    encoding (which operates on 6-bit chunks of data), we only generate
+    0.75 times as many bytes (rounded up) as the number of characters we
+    need and discard any excess characters over the specified length.
+    This ensures full distribution over each character of the salt.
+    """
+    import math
+    import random
+    salt = []
+    for i in xrange(int(math.ceil(salt_len * 0.75))):
+        salt.append(random.randint(0, 255))
+    return _bytes_to_text(_pack_bytes(salt))[:salt_len]
+
 
 def upgrade_legacy_hash(legacy_hash, salt, sep=u"$"):
-   """
-   This utility function is meant to provide a migration path for users
-   of mudpy's legacy account-name-salted MD5 hexdigest password hashes.
-   By passing the old passhash (as legacy_hash) and name (as salt)
-   facets to this function, a conforming new-style password hash will be
-   returned.
-   """
-   import re
-   assert re.match(u"^[0-9a-f]{32}$", legacy_hash), "Not a valid MD5 hexdigest"
-   # this needs to be declared as b"" in 2to3
-   collapsed = ""
-   for i in xrange(16):
-      # this needs to become a byte() call in 2to3
-      collapsed += chr( int(legacy_hash[2*i:2*i+2], 16) )
-   return u"%s%s%s%s%s%s%s%s" % (
-      sep,
-      MD5,
-      sep,
-      0, # 2**0 provides one round of hashing
-      sep,
-      salt,
-      sep,
-      _bytes_to_text(collapsed)
-   )
+    """
+    This utility function is meant to provide a migration path for users
+    of mudpy's legacy account-name-salted MD5 hexdigest password hashes.
+    By passing the old passhash (as legacy_hash) and name (as salt)
+    facets to this function, a conforming new-style password hash will be
+    returned.
+    """
+    import re
+    assert re.match(u"^[0-9a-f]{32}$",
+                    legacy_hash), "Not a valid MD5 hexdigest"
+    # this needs to be declared as b"" in 2to3
+    collapsed = ""
+    for i in xrange(16):
+        # this needs to become a byte() call in 2to3
+        collapsed += chr(int(legacy_hash[2 * i:2 * i + 2], 16))
+    return u"%s%s%s%s%s%s%s%s" % (
+        sep,
+        MD5,
+        sep,
+        0,  # 2**0 provides one round of hashing
+        sep,
+        salt,
+        sep,
+        _bytes_to_text(collapsed)
+    )
+
 
 def create(
-   password,
-   salt=None,
-   algorithm=SHA1,
-   rounds=4,
-   salt_len=2,
-   sep=u"$"
+    password,
+    salt=None,
+    algorithm=SHA1,
+    rounds=4,
+    salt_len=2,
+    sep=u"$"
 ):
-   """
-   The meat of the module, this function takes a provided password and
-   generates a Unix-like passwd hash suitable for storage in portable,
-   text-based data files. The password is prepended with a salt (which
-   can also be specified explicitly, if the output needs to be
-   repeatable) and then hashed with the requested algorithm iterated as
-   many times as 2 raised to the power of the rounds parameter.
-
-   The first character of the text returned by this function denotes the
-   separator character used to identify subsequent fields. The fields in
-   order are:
-
-      1. the decimal index number indicating which algorithm was used,
-         also mapped as convenience constants at the beginning of this
-         module
-
-      2. the number of times (as an exponent of 2) which the algorithm
-         was iterated, represented by a decimal value between 0 and 16
-         inclusive (0 results in one round, 16 results in 65536 rounds,
-         and anything higher than that is a potential resource
-         consumption denial of service on the application anyway)
-
-      3. the plain-text salt with which the password was prepended
-         before hashing
-
-      4. the resulting password hash itself, base64-encoded using . and
-         / as the two non-alpha-numeric characters required to reach 64
-
-   The defaults provided should be safe for everyday use, but something
-   more heavy-duty may be in order for admin users, such as::
-
-      create(password, algorithm=SHA256, rounds=12, salt_len=16)
-   """
-   import hashlib
-
-   # if a specific salt wasn't specified, we need to generate one
-   if not salt:
-      salt = _generate_salt(salt_len=salt_len)
-
-   # make sure the algorithm index number is coerced into integer form,
-   # since it could also be passed as text (in decimal) for convenience
-   algorithm = int(algorithm)
-
-   # the list of algorithms supported by this function corresponds to
-   # the convenience constants defined at the beginning of the module
-   algorithms = {
-      MD5: hashlib.md5,
-      SHA1: hashlib.sha1,
-      SHA224: hashlib.sha224,
-      SHA256: hashlib.sha256,
-      SHA384: hashlib.sha384,
-      SHA512: hashlib.sha512,
-   }
-
-   # make sure the rounds exponent is coerced into integer form, since
-   # it could also be passed as text (in decimal) for convenience
-   rounds = int(rounds)
-
-   # to avoid a potential resource consumption denial of service attack,
-   # only consider values in the range of 0-16
-   assert 0 <= rounds <= 16
-
-   # here is where the salt is prepended to the provided password text
-   hashed = salt+password
-
-   # iterate the hashing algorithm over its own digest the specified
-   # number of times
-   for i in xrange(2**rounds):
-      hashed = algorithms[algorithm](hashed).digest()
-
-   # concatenate the output fields, coercing into text form as needed
-   return u"%s%s%s%s%s%s%s%s" % (
-      sep, algorithm, sep, rounds, sep, salt, sep, _bytes_to_text(hashed)
-   )
+    """
+    The meat of the module, this function takes a provided password and
+    generates a Unix-like passwd hash suitable for storage in portable,
+    text-based data files. The password is prepended with a salt (which
+    can also be specified explicitly, if the output needs to be
+    repeatable) and then hashed with the requested algorithm iterated as
+    many times as 2 raised to the power of the rounds parameter.
+
+    The first character of the text returned by this function denotes the
+    separator character used to identify subsequent fields. The fields in
+    order are:
+
+       1. the decimal index number indicating which algorithm was used,
+          also mapped as convenience constants at the beginning of this
+          module
+
+       2. the number of times (as an exponent of 2) which the algorithm
+          was iterated, represented by a decimal value between 0 and 16
+          inclusive (0 results in one round, 16 results in 65536 rounds,
+          and anything higher than that is a potential resource
+          consumption denial of service on the application anyway)
+
+       3. the plain-text salt with which the password was prepended
+          before hashing
+
+       4. the resulting password hash itself, base64-encoded using . and
+          / as the two non-alpha-numeric characters required to reach 64
+
+    The defaults provided should be safe for everyday use, but something
+    more heavy-duty may be in order for admin users, such as::
+
+       create(password, algorithm=SHA256, rounds=12, salt_len=16)
+    """
+    import hashlib
+
+    # if a specific salt wasn't specified, we need to generate one
+    if not salt:
+        salt = _generate_salt(salt_len=salt_len)
+
+    # make sure the algorithm index number is coerced into integer form,
+    # since it could also be passed as text (in decimal) for convenience
+    algorithm = int(algorithm)
+
+    # the list of algorithms supported by this function corresponds to
+    # the convenience constants defined at the beginning of the module
+    algorithms = {
+        MD5: hashlib.md5,
+        SHA1: hashlib.sha1,
+        SHA224: hashlib.sha224,
+        SHA256: hashlib.sha256,
+        SHA384: hashlib.sha384,
+        SHA512: hashlib.sha512,
+    }
+
+    # make sure the rounds exponent is coerced into integer form, since
+    # it could also be passed as text (in decimal) for convenience
+    rounds = int(rounds)
+
+    # to avoid a potential resource consumption denial of service attack,
+    # only consider values in the range of 0-16
+    assert 0 <= rounds <= 16
+
+    # here is where the salt is prepended to the provided password text
+    hashed = salt + password
+
+    # iterate the hashing algorithm over its own digest the specified
+    # number of times
+    for i in xrange(2 ** rounds):
+        hashed = algorithms[algorithm](hashed).digest()
+
+    # concatenate the output fields, coercing into text form as needed
+    return u"%s%s%s%s%s%s%s%s" % (
+        sep, algorithm, sep, rounds, sep, salt, sep, _bytes_to_text(hashed)
+    )
 
-def verify(password, encoded_hash):
-   """
-   This simple function requires a text password and a mudpy-format
-   password hash (as generated by the create function). It returns True
-   if the password, hashed with the parameters from the encoded_hash,
-   comes out the same as the encoded_hash.
-   """
-   sep = encoded_hash[0]
-   algorithm, rounds, salt, hashed = encoded_hash[1:].split(sep)
-   if encoded_hash == create(
-      password=password,
-      salt=salt,
-      sep=sep,
-      algorithm=algorithm,
-      rounds=rounds
-   ):
-      return True
-   else:
-      return False
 
+def verify(password, encoded_hash):
+    """
+    This simple function requires a text password and a mudpy-format
+    password hash (as generated by the create function). It returns True
+    if the password, hashed with the parameters from the encoded_hash,
+    comes out the same as the encoded_hash.
+    """
+    sep = encoded_hash[0]
+    algorithm, rounds, salt, hashed = encoded_hash[1:].split(sep)
+    if encoded_hash == create(
+       password=password,
+       salt=salt,
+       sep=sep,
+       algorithm=algorithm,
+       rounds=rounds
+       ):
+        return True
+    else:
+        return False