ldap_salted_sha1 assumes a salt length of 4 bytes, when sometimes it can be different lengths

Issue #30 resolved
Former user created an issue
(Imported from Google Code)

misterpib wrote:

What steps will reproduce the problem?
1. Try ldap_salted_sha1.identify on a hash like '{SSHA}UDrXYV0JVaVPgiydBmHZpWnHamxsb25nc2FsdA==' ('hello' with a salt of 'longsalt', made with '{SSHA}' + (sha1('hello' + 'longsalt').digest() + 'longsalt').encode('base64').strip())
2. See that it returns False

What is the expected output? What do you see instead?

It should return true, and be able to verify passwords against the hash.

What version of the product are you using?

Latest released version from PyPI

Please provide any additional information below.

Different systems generate hashes with different salt lengths, so it would be nice to be able to use those with passlib.

Comments (4)

  1. Anonymous
    (Imported from Google Code)

    misterpib wrote:

    A fixed version, allowing up to 10 bytes in the salt (some {SSHA} implementations use up to 9 bytes for the salt, so I've read).

    class ldap_salted_sha1(_SaltedBase64DigestHelper):

    """This class stores passwords using LDAP's salted SHA1 format,

    and follows the :ref:password-hash-api.

    It supports a 4-to-10-byte salt.

    The :meth:encrypt() and :meth:genconfig methods accept the

    following optional keyword:

    :param salt:

    Optional salt string.

    If not specified, one will be autogenerated (this is recommended).

    If specified, it must be a 4-10 byte string; each byte may have any

    value from 0x00 .. 0xff.

    """

    name = "ldap_salted_sha1"

    ident = u"{SSHA}"

    _hash_func = sha1

    _pat = re.compile(ur"^\{SSHA\}(?P [+/a-zA-Z0-9=]{32,40})$")

    _stub_checksum = b('\x00') * 20

    min_salt_size = 4

    max_salt_size = 10

    @­classmethod

    def from_string(cls, hash):

    if not hash:

    raise ValueError("no hash specified")

    if isinstance(hash, bytes):

    hash = hash.decode('ascii')

    m = cls._pat.match(hash)

    if not m:

    raise ValueError("not a %s hash" % (cls.name,))

    data = b64decode(m.group("tmp").encode("ascii"))

    chk, salt = data[:20], data[20:]

    return cls(checksum=chk, salt=salt, strict=True)

  2. Eli Collins repo owner
    (Imported from Google Code)

    Thanks for reporting that... documentation on the real-world use of the LDAP hash formats is scarce. As of r89992826f53a, the ldap_salted_(md5|sha1) hash formats can now handle variable-length salts. This change should be included in Passlib 1.6, which I'm hoping to release in the next week or so.

  3. Eli Collins repo owner
    (Imported from Google Code)

    Passlib 1.6 has been released, and includes support for 4-16 byte salts (though this can be raised using monkeypatching by setting ldap_salted_sha1.max_salt_size). When calling encrypt(), the salt size can be set with the 'salt_size=xxx' keyword.

  4. Log in to comment