Exemple #1
0
    def test_lookup_hash_alt_types(self):
        """lookup_hash() -- alternate types"""

        from passlib.crypto.digest import lookup_hash

        info = lookup_hash("sha256")
        self.assertIs(lookup_hash(info), info)
        self.assertIs(lookup_hash(info.const), info)

        self.assertRaises(TypeError, lookup_hash, 123)
    def test_lookup_hash_alt_types(self):
        """lookup_hash() -- alternate types"""

        from passlib.crypto.digest import lookup_hash

        info = lookup_hash("sha256")
        self.assertIs(lookup_hash(info), info)
        self.assertIs(lookup_hash(info.const), info)

        self.assertRaises(TypeError, lookup_hash, 123)
    def test_lookup_hash_ctor(self):
        """lookup_hash() -- constructor"""
        from passlib.crypto.digest import lookup_hash

        # invalid/unknown names should be rejected
        self.assertRaises(ValueError, lookup_hash, "new")
        self.assertRaises(ValueError, lookup_hash, "__name__")
        self.assertRaises(ValueError, lookup_hash, "sha4")

        # 1. should return hashlib builtin if found
        self.assertEqual(lookup_hash("md5"), (hashlib.md5, 16, 64))

        # 2. should return wrapper around hashlib.new() if found
        try:
            hashlib.new("sha")
            has_sha = True
        except ValueError:
            has_sha = False
        if has_sha:
            record = lookup_hash("sha")
            const = record[0]
            self.assertEqual(record, (const, 20, 64))
            self.assertEqual(
                hexlify(const(b"abc").digest()),
                b"0164b8a914cd2a5e74c4f7ff082c4d97f1edf880",
            )

        else:
            self.assertRaises(ValueError, lookup_hash, "sha")

        # 3. should fall back to builtin md4
        try:
            hashlib.new("md4")
            has_md4 = True
        except ValueError:
            has_md4 = False
        record = lookup_hash("md4")
        const = record[0]
        if not has_md4:
            from passlib.crypto._md4 import md4

            self.assertIs(const, md4)
        self.assertEqual(record, (const, 16, 64))
        self.assertEqual(
            hexlify(const(b"abc").digest()), b"a448017aaf21d8525fc10ae87aa6729d"
        )

        # 4. unknown names should be rejected
        self.assertRaises(ValueError, lookup_hash, "xxx256")

        # should memoize records
        self.assertIs(lookup_hash("md5"), lookup_hash("md5"))
    def test_lookup_hash_ctor(self):
        """lookup_hash() -- constructor"""
        from passlib.crypto.digest import lookup_hash

        # invalid/unknown names should be rejected
        self.assertRaises(ValueError, lookup_hash, "new")
        self.assertRaises(ValueError, lookup_hash, "__name__")
        self.assertRaises(ValueError, lookup_hash, "sha4")

        # 1. should return hashlib builtin if found
        self.assertEqual(lookup_hash("md5"), (hashlib.md5, 16, 64))

        # 2. should return wrapper around hashlib.new() if found
        try:
            hashlib.new("sha")
            has_sha = True
        except ValueError:
            has_sha = False
        if has_sha:
            record = lookup_hash("sha")
            const = record[0]
            self.assertEqual(record, (const, 20, 64))
            self.assertEqual(hexlify(const(b"abc").digest()),
                             b"0164b8a914cd2a5e74c4f7ff082c4d97f1edf880")

        else:
            self.assertRaises(ValueError, lookup_hash, "sha")

        # 3. should fall back to builtin md4
        try:
            hashlib.new("md4")
            has_md4 = True
        except ValueError:
            has_md4 = False
        record = lookup_hash("md4")
        const = record[0]
        if not has_md4:
            from passlib.crypto._md4 import md4
            self.assertIs(const, md4)
        self.assertEqual(record, (const, 16, 64))
        self.assertEqual(hexlify(const(b"abc").digest()),
                         b"a448017aaf21d8525fc10ae87aa6729d")

        # 4. unknown names should be rejected
        self.assertRaises(ValueError, lookup_hash, "xxx256")

        # should memoize records
        self.assertIs(lookup_hash("md5"), lookup_hash("md5"))
Exemple #5
0
def create_hex_hash(digest, module=__name__, django_name=None, required=True):
    """
    create hex-encoded unsalted hasher for specified digest algorithm.

    .. versionchanged:: 1.7.3
        If called with unknown/supported digest, won't throw error immediately,
        but instead return a dummy hasher that will throw error when called.

        set ``required=True`` to restore old behavior.
    """
    info = lookup_hash(digest, required=required)
    name = "hex_" + info.name
    if not info.supported:
        info.digest_size = 0
    hasher = type(
        name,
        (HexDigestHash, ),
        dict(
            name=name,
            __module__=module,  # so ABCMeta won't clobber it
            # sometimes it's a function, sometimes not. so wrap it.
            _hash_func=staticmethod(info.const),
            checksum_size=info.digest_size * 2,
            __doc__=
            """This class implements a plain hexadecimal %s hash, and follows the :ref:`password-hash-api`.

It supports no optional or contextual keywords.
""" % (info.name, )))
    if not info.supported:
        hasher.supported = False
    if django_name:
        hasher.django_name = django_name
    return hasher
Exemple #6
0
def get_prf(name):
    """Lookup pseudo-random family (PRF) by name.

    :arg name:
        This must be the name of a recognized prf.
        Currently this only recognizes names with the format
        :samp:`hmac-{digest}`, where :samp:`{digest}`
        is the name of a hash function such as
        ``md5``, ``sha256``, etc.

        todo: restore text about callables.

    :raises ValueError: if the name is not known
    :raises TypeError: if the name is not a callable or string

    :returns:
        a tuple of :samp:`({prf_func}, {digest_size})`, where:

        * :samp:`{prf_func}` is a function implementing
          the specified PRF, and has the signature
          ``prf_func(secret, message) -> digest``.

        * :samp:`{digest_size}` is an integer indicating
          the number of bytes the function returns.

    Usage example::

        >>> from passlib.utils.pbkdf2 import get_prf
        >>> hmac_sha256, dsize = get_prf("hmac-sha256")
        >>> hmac_sha256
        <function hmac_sha256 at 0x1e37c80>
        >>> dsize
        32
        >>> digest = hmac_sha256('password', 'message')

    .. deprecated:: 1.7

        This function is deprecated, and will be removed in Passlib 2.0.
        This only related replacement is :func:`passlib.crypto.digest.compile_hmac`.
    """
    global _prf_cache
    if name in _prf_cache:
        return _prf_cache[name]
    if isinstance(name, native_string_types):
        if not name.startswith(_HMAC_PREFIXES):
            raise ValueError("unknown prf algorithm: %r" % (name, ))
        digest = lookup_hash(name[5:]).name

        def hmac(key, msg):
            return compile_hmac(digest, key)(msg)

        record = (hmac, hmac.digest_info.digest_size)
    elif callable(name):
        # assume it's a callable, use it directly
        digest_size = len(name(b'x', b'y'))
        record = (name, digest_size)
    else:
        raise ExpectedTypeError(name, "str or callable", "prf name")
    _prf_cache[name] = record
    return record
Exemple #7
0
def get_prf(name):
    """Lookup pseudo-random family (PRF) by name.

    :arg name:
        This must be the name of a recognized prf.
        Currently this only recognizes names with the format
        :samp:`hmac-{digest}`, where :samp:`{digest}`
        is the name of a hash function such as
        ``md5``, ``sha256``, etc.

        todo: restore text about callables.

    :raises ValueError: if the name is not known
    :raises TypeError: if the name is not a callable or string

    :returns:
        a tuple of :samp:`({prf_func}, {digest_size})`, where:

        * :samp:`{prf_func}` is a function implementing
          the specified PRF, and has the signature
          ``prf_func(secret, message) -> digest``.

        * :samp:`{digest_size}` is an integer indicating
          the number of bytes the function returns.

    Usage example::

        >>> from passlib.utils.pbkdf2 import get_prf
        >>> hmac_sha256, dsize = get_prf("hmac-sha256")
        >>> hmac_sha256
        <function hmac_sha256 at 0x1e37c80>
        >>> dsize
        32
        >>> digest = hmac_sha256('password', 'message')

    .. deprecated:: 1.7

        This function is deprecated, and will be removed in Passlib 2.0.
        This only related replacement is :func:`passlib.crypto.digest.compile_hmac`.
    """
    global _prf_cache
    if name in _prf_cache:
        return _prf_cache[name]
    if isinstance(name, native_string_types):
        if not name.startswith(_HMAC_PREFIXES):
            raise ValueError("unknown prf algorithm: %r" % (name,))
        digest = lookup_hash(name[5:]).name
        def hmac(key, msg):
            return compile_hmac(digest, key)(msg)
        record = (hmac, hmac.digest_info.digest_size)
    elif callable(name):
        # assume it's a callable, use it directly
        digest_size = len(name(b'x', b'y'))
        record = (name, digest_size)
    else:
        raise ExpectedTypeError(name, "str or callable", "prf name")
    _prf_cache[name] = record
    return record
Exemple #8
0
    def test_lookup_hash_metadata(self):
        """lookup_hash() -- metadata"""

        from passlib.crypto.digest import lookup_hash

        # quick test of metadata using known reference - sha256
        info = lookup_hash("sha256")
        self.assertEqual(info.name, "sha256")
        self.assertEqual(info.iana_name, "sha-256")
        self.assertEqual(info.block_size, 64)
        self.assertEqual(info.digest_size, 32)
        self.assertIs(lookup_hash("SHA2-256"), info)

        # quick test of metadata using known reference - md5
        info = lookup_hash("md5")
        self.assertEqual(info.name, "md5")
        self.assertEqual(info.iana_name, "md5")
        self.assertEqual(info.block_size, 64)
        self.assertEqual(info.digest_size, 16)
Exemple #9
0
    def test_lookup_hash_w_unknown_name(self):
        """lookup_hash() -- unknown hash name"""
        from passlib.crypto.digest import lookup_hash

        # unknown names should be rejected by default
        self.assertRaises(UnknownHashError, lookup_hash, "xxx256")

        # required=False should return stub record instead
        info = lookup_hash("xxx256", required=False)
        self.assertFalse(info.supported)
        self.assertRaisesRegex(UnknownHashError, "unknown hash: 'xxx256'",
                               info.const)
        self.assertEqual(info.name, "xxx256")
        self.assertEqual(info.digest_size, None)
        self.assertEqual(info.block_size, None)

        # should cache stub records
        info2 = lookup_hash("xxx256", required=False)
        self.assertIs(info2, info)
    def test_lookup_hash_metadata(self):
        """lookup_hash() -- metadata"""

        from passlib.crypto.digest import lookup_hash

        # quick test of metadata using known reference - sha256
        info = lookup_hash("sha256")
        self.assertEqual(info.name, "sha256")
        self.assertEqual(info.iana_name, "sha-256")
        self.assertEqual(info.block_size, 64)
        self.assertEqual(info.digest_size, 32)
        self.assertIs(lookup_hash("SHA2-256"), info)

        # quick test of metadata using known reference - md5
        info = lookup_hash("md5")
        self.assertEqual(info.name, "md5")
        self.assertEqual(info.iana_name, "md5")
        self.assertEqual(info.block_size, 64)
        self.assertEqual(info.digest_size, 16)
Exemple #11
0
    def test_mock_fips_mode(self):
        """
        lookup_hash() -- test set_mock_fips_mode()
        """
        from passlib.crypto.digest import lookup_hash, _set_mock_fips_mode

        # check if md5 is available so we can test mock helper
        if not lookup_hash("md5", required=False).supported:
            raise self.skipTest("md5 not supported")

        # enable monkeypatch to mock up fips mode
        _set_mock_fips_mode()
        self.addCleanup(_set_mock_fips_mode, False)

        pat = "'md5' hash disabled for fips"
        self.assertRaisesRegex(UnknownHashError, pat, lookup_hash, "md5")

        info = lookup_hash("md5", required=False)
        self.assertRegex(info.error_text, pat)
        self.assertRaisesRegex(UnknownHashError, pat, info.const)

        # should use hardcoded fallback info
        self.assertEqual(info.digest_size, 16)
        self.assertEqual(info.block_size, 64)
Exemple #12
0
def create_hex_hash(digest, module=__name__):
    # NOTE: could set digest_name=hash.name for cpython, but not for some other platforms.
    info = lookup_hash(digest)
    name = "hex_" + info.name
    return type(
        name,
        (HexDigestHash, ),
        dict(
            name=name,
            __module__=module,  # so ABCMeta won't clobber it
            _hash_func=staticmethod(
                info.const
            ),  # sometimes it's a function, sometimes not. so wrap it.
            checksum_size=info.digest_size * 2,
            __doc__=
            """This class implements a plain hexadecimal %s hash, and follows the :ref:`password-hash-api`.

It supports no optional or contextual keywords.
""" % (info.name, )))
Exemple #13
0
 def get_md4_const(self):
     """
     get md4 constructor --
     overridden by subclasses to use alternate backends.
     """
     return lookup_hash("md4").const
Exemple #14
0
# =============================================================================
# imports
# =============================================================================
# core
from binascii import hexlify
import logging

log = logging.getLogger(__name__)
from warnings import warn
# site
# pkg
from passlib.utils import to_unicode, right_pad_string
from passlib.utils.compat import unicode
from passlib.crypto.digest import lookup_hash

md4 = lookup_hash("md4").const
import passlib.utils.handlers as uh

# local
__all__ = [
    "lmhash",
    "nthash",
    "bsd_nthash",
    "msdcc",
    "msdcc2",
]


# =============================================================================
# lanman hash
# =============================================================================
 def get_md4_const(self):
     """
     get md4 constructor --
     overridden by subclasses to use alternate backends.
     """
     return lookup_hash("md4").const
Exemple #16
0
"""
passlib.utils.md4 - DEPRECATED MODULE, WILL BE REMOVED IN 2.0

MD4 should now be looked up through ``passlib.crypto.digest.lookup_hash("md4").const``,
which provides unified handling stdlib implementation (if present).
"""
#=============================================================================
# issue deprecation warning for module
#=============================================================================
from warnings import warn
warn("the module 'passlib.utils.md4' is deprecated as of Passlib 1.7, "
     "and will be removed in Passlib 2.0, please use "
     "'lookup_hash(\"md4\").const()' from 'passlib.crypto' instead",
     DeprecationWarning)

#=============================================================================
# backwards compat exports
#=============================================================================
__all__ = ["md4"]

# this should use hashlib version if available,
# and fall back to builtin version.
from passlib.crypto.digest import lookup_hash
md4 = lookup_hash("md4").const
del lookup_hash

#=============================================================================
# eof
#=============================================================================