Exemple #1
0
def _load():
    global _get_category

    # TODO: would like to add support for inheriting config from a preset
    #       (or from existing hasher state) and letting PASSLIB_CONFIG
    #       be an update, not a replacement.

    # TODO: wrap and import any custom hashers as passlib handlers,
    #       so they could be used in the passlib config.

    # load config from settings
    _UNSET = object()
    config = getattr(settings, "PASSLIB_CONFIG", _UNSET)
    if config is _UNSET:
        # XXX: should probably deprecate this alias
        config = getattr(settings, "PASSLIB_CONTEXT", _UNSET)
    if config is _UNSET:
        config = "passlib-default"
    if config is None:
        warn(
            "setting PASSLIB_CONFIG=None is deprecated, "
            "and support will be removed in Passlib 1.8, "
            "use PASSLIB_CONFIG='disabled' instead.", DeprecationWarning)
        config = "disabled"
    elif not isinstance(config, (unicode, bytes, dict)):
        raise ExpectedTypeError(config, "str or dict", "PASSLIB_CONFIG")

    # load custom category func (if any)
    get_category = getattr(settings, "PASSLIB_GET_CATEGORY", None)
    if get_category and not callable(get_category):
        raise ExpectedTypeError(get_category, "callable",
                                "PASSLIB_GET_CATEGORY")

    # check if we've been disabled
    if config == "disabled":
        if _patched:  # pragma: no cover -- sanity check
            log.error("didn't expect monkeypatching would be applied!")
        _remove_patch()
        return

    # resolve any preset aliases
    if isinstance(config, str) and '\n' not in config:
        config = get_preset_config(config)

    # setup context
    _apply_patch()
    password_context.load(config)
    if get_category:
        # NOTE: _get_category is module global which is read by
        #       monkeypatched functions constructed by _apply_patch()
        _get_category = get_category
    log.debug("passlib.ext.django loaded")
Exemple #2
0
def pbkdf1(secret, salt, rounds, keylen=None, hash="sha1"):
    """pkcs#5 password-based key derivation v1.5

    :arg secret: passphrase to use to generate key
    :arg salt: salt string to use when generating key
    :param rounds: number of rounds to use to generate key
    :arg keylen: number of bytes to generate (if ``None``, uses digest's native size)
    :param hash:
        hash function to use. must be name of a hash recognized by hashlib.

    :returns:
        raw bytes of generated key

    .. note::

        This algorithm has been deprecated, new code should use PBKDF2.
        Among other limitations, ``keylen`` cannot be larger
        than the digest size of the specified hash.
    """
    # validate secret & salt
    if not isinstance(secret, bytes):
        raise ExpectedTypeError(secret, "bytes", "secret")
    if not isinstance(salt, bytes):
        raise ExpectedTypeError(salt, "bytes", "salt")

    # validate rounds
    if not isinstance(rounds, int_types):
        raise ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # resolve hash
    const, digest_size, block_size = get_hash_info(hash)

    # validate keylen
    if keylen is None:
        keylen = digest_size
    elif not isinstance(keylen, int_types):
        raise ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 0:
        raise ValueError("keylen must be at least 0")
    elif keylen > digest_size:
        raise ValueError("keylength too large for digest: %r > %r" %
                         (keylen, digest_size))

    # main pbkdf1 loop
    block = secret + salt
    for _ in irange(rounds):
        block = const(block).digest()
    return block[:keylen]
Exemple #3
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 #4
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.

        this can also be a callable with the signature
        ``prf(secret, message) -> digest``,
        in which case it will be returned unchanged.

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

    :returns:
        a tuple of :samp:`({func}, {digest_size})`.

        * :samp:`{func}` is a function implementing
          the specified prf, and has the signature
          ``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')

    this function will attempt to return the fastest implementation
    it can find; if M2Crypto is present, and supports the specified prf,
    :func:`M2Crypto.EVP.hmac` will be used behind the scenes.
    """
    global _prf_cache
    if name in _prf_cache:
        return _prf_cache[name]
    if isinstance(name, str):
        if name.startswith("hmac-") or name.startswith("hmac_"):
            retval = _get_hmac_prf(name[5:])
        else:
            raise ValueError("unknown prf algorithm: %r" % (name,))
    elif callable(name):
        # assume it's a callable, use it directly
        digest_size = len(name(b('x'),b('y')))
        retval = (name, digest_size)
    else:
        raise ExpectedTypeError(name, "str or callable", "prf name")
    _prf_cache[name] = retval
    return retval
def register_crypt_handler(handler, force=False, _attr=None):
    """register password hash handler.

    this method immediately registers a handler with the internal passlib registry,
    so that it will be returned by :func:`get_crypt_handler` when requested.

    :arg handler: the password hash handler to register
    :param force: force override of existing handler (defaults to False)
    :param _attr:
        [internal kwd] if specified, ensures ``handler.name``
        matches this value, or raises :exc:`ValueError`.

    :raises TypeError:
        if the specified object does not appear to be a valid handler.

    :raises ValueError:
        if the specified object's name (or other required attributes)
        contain invalid values.

    :raises KeyError:
        if a (different) handler was already registered with
        the same name, and ``force=True`` was not specified.
    """
    # validate handler
    if not is_crypt_handler(handler):
        raise ExpectedTypeError(handler, "password hash handler", "handler")
    if not handler:
        raise AssertionError("``bool(handler)`` must be True")

    # validate name
    name = handler.name
    _validate_handler_name(name)
    if _attr and _attr != name:
        raise ValueError(
            "handlers must be stored only under their own name (%r != %r)" %
            (_attr, name))

    # check for existing handler
    other = _handlers.get(name)
    if other:
        if other is handler:
            log.debug("same %r handler already registered: %r", name, handler)
            return
        elif force:
            log.warning("overriding previously registered %r handler: %r",
                        name, other)
        else:
            raise KeyError(
                "another %r handler has already been registered: %r" %
                (name, other))

    # register handler
    _handlers[name] = handler
    log.debug("registered %r handler: %r", name, handler)
Exemple #6
0
def pbkdf2(secret, salt, rounds, keylen=None, prf="hmac-sha1"):
    """pkcs#5 password-based key derivation v2.0

    :arg secret: passphrase to use to generate key
    :arg salt: salt string to use when generating key
    :param rounds: number of rounds to use to generate key
    :arg keylen:
        number of bytes to generate.
        if set to ``None``, will use digest size of selected prf.
    :param prf:
        psuedo-random family to use for key strengthening.
        this can be any string or callable accepted by :func:`get_prf`.
        this defaults to ``"hmac-sha1"`` (the only prf explicitly listed in
        the PBKDF2 specification)

    :returns:
        raw bytes of generated key
    """
    # validate secret & salt
    if not isinstance(secret, bytes):
        raise ExpectedTypeError(secret, "bytes", "secret")
    if not isinstance(salt, bytes):
        raise ExpectedTypeError(salt, "bytes", "salt")

    # validate rounds
    if not isinstance(rounds, int_types):
        raise ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # validate keylen
    if keylen is not None:
        if not isinstance(keylen, int_types):
            raise ExpectedTypeError(keylen, "int or None", "keylen")
        elif keylen < 0:
            raise ValueError("keylen must be at least 0")

    # special case for m2crypto + hmac-sha1
    if prf == "hmac-sha1" and _EVP:
        if keylen is None:
            keylen = 20
        # NOTE: doing check here, because M2crypto won't take 'long' instances
        # (which this is when running under 32bit)
        if keylen > MAX_HMAC_SHA1_KEYLEN:
            raise ValueError("key length too long for digest")

        # NOTE: as of 2012-4-4, m2crypto has buffer overflow issue
        # which may cause segfaults if keylen > 32 (EVP_MAX_KEY_LENGTH).
        # therefore we're avoiding m2crypto for large keys until that's fixed.
        # see https://bugzilla.osafoundation.org/show_bug.cgi?id=13052
        if keylen < 32:
            return _EVP.pbkdf2(secret, salt, rounds, keylen)

    # resolve prf
    prf_func, digest_size = get_prf(prf)
    if keylen is None:
        keylen = digest_size

    # figure out how many blocks we'll need
    block_count = (keylen+digest_size-1)//digest_size
    if block_count >= MAX_BLOCKS:
        raise ValueError("key length too long for digest")

    # build up result from blocks
    def gen():
        for i in irange(block_count):
            digest = prf_func(secret, salt + pack(">L", i+1))
            accum = bytes_to_int(digest)
            for _ in irange(rounds-1):
                digest = prf_func(secret, digest)
                accum ^= bytes_to_int(digest)
            yield int_to_bytes(accum, digest_size)
    return join_bytes(gen())[:keylen]
Exemple #7
0
def pbkdf1(secret, salt, rounds, keylen=None, hash="sha1"):
    """pkcs#5 password-based key derivation v1.5

    :arg secret: passphrase to use to generate key
    :arg salt: salt string to use when generating key
    :param rounds: number of rounds to use to generate key
    :arg keylen: number of bytes to generate (if ``None``, uses digest's native size)
    :param hash:
        hash function to use. must be name of a hash recognized by hashlib.

    :returns:
        raw bytes of generated key

    .. note::

        This algorithm has been deprecated, new code should use PBKDF2.
        Among other limitations, ``keylen`` cannot be larger
        than the digest size of the specified hash.

    """
    # validate secret & salt
    if not isinstance(secret, bytes):
        raise ExpectedTypeError(secret, "bytes", "secret")
    if not isinstance(salt, bytes):
        raise ExpectedTypeError(salt, "bytes", "salt")

    # validate rounds
    if not isinstance(rounds, int_types):
        raise ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # resolve hash
    try:
        hash_const = getattr(hashlib, hash)
    except AttributeError:
        # check for ssl hash
        # NOTE: if hash unknown, new() will throw ValueError, which we'd just
        #       reraise anyways; so instead of checking, we just let it get
        #       thrown during first use, below
        # TODO: use builtin md4 class if hashlib doesn't have it.
        def hash_const(msg):
            return hashlib.new(hash, msg)

    # prime pbkdf1 loop, get block size
    block = hash_const(secret + salt).digest()

    # validate keylen
    if keylen is None:
        keylen = len(block)
    elif not isinstance(keylen, int_types):
        raise ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 0:
        raise ValueError("keylen must be at least 0")
    elif keylen > len(block):
        raise ValueError("keylength too large for digest: %r > %r" %
                         (keylen, len(block)))

    # main pbkdf1 loop
    for _ in irange(rounds-1):
        block = hash_const(block).digest()
    return block[:keylen]
Exemple #8
0
def utf8_truncate(source, index):
    """
    helper to truncate UTF8 byte string to nearest character boundary ON OR AFTER <index>.
    returned prefix will always have length of at least <index>, and will stop on the
    first byte that's not a UTF8 continuation byte (128 - 191 inclusive).
    since utf8 should never take more than 4 bytes to encode known unicode values,
    we can stop after ``index+3`` is reached.

    :param bytes source:
    :param int index:
    :rtype: bytes
    """
    # general approach:
    #
    # * UTF8 bytes will have high two bits (0xC0) as one of:
    #   00 -- ascii char
    #   01 -- ascii char
    #   10 -- continuation of multibyte char
    #   11 -- start of multibyte char.
    #   thus we can cut on anything where high bits aren't "10" (0x80; continuation byte)
    #
    # * UTF8 characters SHOULD always be 1 to 4 bytes, though they may be unbounded.
    #   so we just keep going until first non-continuation byte is encountered, or end of str.
    #   this should work predictably even for malformed/non UTF8 inputs.

    if not isinstance(source, bytes):
        raise ExpectedTypeError(source, bytes, "source")

    # validate index
    end = len(source)
    if index < 0:
        index = max(0, index + end)
    if index >= end:
        return source

    # can stop search after 4 bytes, won't ever have longer utf8 sequence.
    end = min(index + 3, end)

    # loop until we find non-continuation byte
    while index < end:
        if byte_elem_value(source[index]) & 0xC0 != 0x80:
            # found single-char byte, or start-char byte.
            break
        # else: found continuation byte.
        index += 1
    else:
        assert index == end

    # truncate at final index
    result = source[:index]

    def sanity_check():
        # try to decode source
        try:
            text = source.decode("utf-8")
        except UnicodeDecodeError:
            # if source isn't valid utf8, byte level match is enough
            return True

        # validate that result was cut on character boundary
        assert text.startswith(result.decode("utf-8"))
        return True

    assert sanity_check()

    return result
Exemple #9
0
def pbkdf2(secret, salt, rounds, keylen=None, prf="hmac-sha1"):
    """pkcs#5 password-based key derivation v2.0

    :arg secret: passphrase to use to generate key
    :arg salt: salt string to use when generating key
    :param rounds: number of rounds to use to generate key
    :arg keylen:
        number of bytes to generate.
        if set to ``None``, will use digest size of selected prf.
    :param prf:
        psuedo-random family to use for key strengthening.
        this can be any string or callable accepted by :func:`get_prf`.
        this defaults to ``"hmac-sha1"`` (the only prf explicitly listed in
        the PBKDF2 specification)

    :returns:
        raw bytes of generated key
    """
    # validate secret & salt
    if not isinstance(secret, bytes):
        raise ExpectedTypeError(secret, "bytes", "secret")
    if not isinstance(salt, bytes):
        raise ExpectedTypeError(salt, "bytes", "salt")

    # validate rounds
    if not isinstance(rounds, int_types):
        raise ExpectedTypeError(rounds, "int", "rounds")
    if rounds < 1:
        raise ValueError("rounds must be at least 1")

    # generated keyed prf helper
    keyed_prf, digest_size = get_keyed_prf(prf, secret)

    # validate keylen
    if keylen is None:
        keylen = digest_size
    elif not isinstance(keylen, int_types):
        raise ExpectedTypeError(keylen, "int or None", "keylen")
    elif keylen < 0:
        raise ValueError("keylen must be at least 0")

    # m2crypto's pbkdf2-hmac-sha1 is faster than ours, so use it if available.
    # NOTE: as of 2012-4-4, m2crypto has buffer overflow issue which frequently
    #       causes segfaults if keylen > 32 (EVP_MAX_KEY_LENGTH).
    #       therefore we're avoiding m2crypto for large keys until that's fixed.
    #       (https://bugzilla.osafoundation.org/show_bug.cgi?id=13052)
    if prf == "hmac-sha1" and _EVP and keylen < 32:
        return _EVP.pbkdf2(secret, salt, rounds, keylen)

    # work out min block count s.t. keylen <= block_count * digest_size
    block_count = (keylen + digest_size - 1) // digest_size
    if block_count >= _MAX_BLOCKS:
        raise ValueError("keylen too long for digest")

    # build up result from blocks
    def gen():
        for i in irange(block_count):
            digest = keyed_prf(salt + pack(">L", i + 1))
            accum = bytes_to_int(digest)
            # speed-critical loop of pbkdf2
            # NOTE: currently converting digests to integers since that XORs faster.
            for _ in irange(rounds - 1):
                digest = keyed_prf(digest)
                accum ^= bytes_to_int(digest)
            yield int_to_bytes(accum, digest_size)

    return join_bytes(gen())[:keylen]