/usr/share/pyshared/passlib/handlers/digests.py is in python-passlib 1.6.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | """passlib.handlers.digests - plain hash digests
"""
#=============================================================================
# imports
#=============================================================================
# core
import hashlib
import logging; log = logging.getLogger(__name__)
from warnings import warn
# site
# pkg
from passlib.utils import to_native_str, to_bytes, render_bytes, consteq
from passlib.utils.compat import bascii_to_str, bytes, unicode, str_to_uascii
import passlib.utils.handlers as uh
from passlib.utils.md4 import md4
# local
__all__ = [
"create_hex_hash",
"hex_md4",
"hex_md5",
"hex_sha1",
"hex_sha256",
"hex_sha512",
]
#=============================================================================
# helpers for hexidecimal hashes
#=============================================================================
class HexDigestHash(uh.StaticHandler):
"this provides a template for supporting passwords stored as plain hexidecimal hashes"
#===================================================================
# class attrs
#===================================================================
_hash_func = None # hash function to use - filled in by create_hex_hash()
checksum_size = None # filled in by create_hex_hash()
checksum_chars = uh.HEX_CHARS
#===================================================================
# methods
#===================================================================
@classmethod
def _norm_hash(cls, hash):
return hash.lower()
def _calc_checksum(self, secret):
if isinstance(secret, unicode):
secret = secret.encode("utf-8")
return str_to_uascii(self._hash_func(secret).hexdigest())
#===================================================================
# eoc
#===================================================================
def create_hex_hash(hash, digest_name, module=__name__):
# NOTE: could set digest_name=hash.name for cpython, but not for some other platforms.
h = hash()
name = "hex_" + digest_name
return type(name, (HexDigestHash,), dict(
name=name,
__module__=module, # so ABCMeta won't clobber it
_hash_func=staticmethod(hash), # sometimes it's a function, sometimes not. so wrap it.
checksum_size=h.digest_size*2,
__doc__="""This class implements a plain hexidecimal %s hash, and follows the :ref:`password-hash-api`.
It supports no optional or contextual keywords.
""" % (digest_name,)
))
#=============================================================================
# predefined handlers
#=============================================================================
hex_md4 = create_hex_hash(md4, "md4")
hex_md5 = create_hex_hash(hashlib.md5, "md5")
hex_md5.django_name = "unsalted_md5"
hex_sha1 = create_hex_hash(hashlib.sha1, "sha1")
hex_sha256 = create_hex_hash(hashlib.sha256, "sha256")
hex_sha512 = create_hex_hash(hashlib.sha512, "sha512")
#=============================================================================
# htdigest
#=============================================================================
class htdigest(uh.PasswordHash):
"""htdigest hash function.
.. todo::
document this hash
"""
name = "htdigest"
setting_kwds = ()
context_kwds = ("user", "realm", "encoding")
default_encoding = "utf-8"
@classmethod
def encrypt(cls, secret, user, realm, encoding=None):
# NOTE: this was deliberately written so that raw bytes are passed through
# unchanged, the encoding kwd is only used to handle unicode values.
if not encoding:
encoding = cls.default_encoding
uh.validate_secret(secret)
if isinstance(secret, unicode):
secret = secret.encode(encoding)
user = to_bytes(user, encoding, "user")
realm = to_bytes(realm, encoding, "realm")
data = render_bytes("%s:%s:%s", user, realm, secret)
return hashlib.md5(data).hexdigest()
@classmethod
def _norm_hash(cls, hash):
"normalize hash to native string, and validate it"
hash = to_native_str(hash, param="hash")
if len(hash) != 32:
raise uh.exc.MalformedHashError(cls, "wrong size")
for char in hash:
if char not in uh.LC_HEX_CHARS:
raise uh.exc.MalformedHashError(cls, "invalid chars in hash")
return hash
@classmethod
def verify(cls, secret, hash, user, realm, encoding="utf-8"):
hash = cls._norm_hash(hash)
other = cls.encrypt(secret, user, realm, encoding)
return consteq(hash, other)
@classmethod
def identify(cls, hash):
try:
cls._norm_hash(hash)
except ValueError:
return False
return True
@classmethod
def genconfig(cls):
return None
@classmethod
def genhash(cls, secret, config, user, realm, encoding="utf-8"):
if config is not None:
cls._norm_hash(config)
return cls.encrypt(secret, user, realm, encoding)
#=============================================================================
# eof
#=============================================================================
|