Skip to content

passlib.hash.fshp - Fairly Secure Hashed Password

Note

While the SHA-2 variants of PBKDF1 have no critical security vulnerabilities, PBKDF1 itself has been deprecated in favor of its successor, PBKDF2. Furthermore, FSHP has been listed as insecure by its author (for unspecified reasons); so this scheme should probably only be used to support existing hashes.

The Fairly Secure Hashed Password (FSHP) scheme 1 is a cross-platform hash based on PBKDF1 2, and uses an LDAP-style hash format. It features a variable length salt, variable rounds, and support for cryptographic hashes from SHA-1 up to SHA-512. This class supports the standard Passlib options for rounds and salt, as well as a special digest keyword for selecting the variant of FSHP to use. It can be used directly as follows:

from passlib.hash import fshp

# generate new salt, hash password
hash = fshp.hash("password")
print(hash)
# > '{FSHP1|16|16384}PtoqcGUetmVEy/uR8715TNqKa8+teMF9qZO1lA9lJNUm1EQBLPZ+qPRLeEPHqy6C'

# the same, but with an explicit number of rounds, larger salt, and specific variant
hashed = fshp.using(rounds=40000, salt_size=32, variant="sha512").hash("password")
print(hashed)
# > '{FSHP3|32|40000}cB8yE/CuADSgUTQZjWy+YTf/cvbU11D/rHNKiUiB6z4dIaO77U/rmNWpgZcZllZbCra5GJ8ZfFRNwCHirPqvYTAnbaQQeFQbWym/frRrRev3buoygFQRYexl4091Pc5m'

# verify password
print(fshp.verify("password", hash))
# > True
print(fshp.verify("secret", hash))
# > False

Tip

the generic PasswordHash usage examples

Interface

fshp

fshp(variant=None, **kwds)

This class implements the FSHP password hash, and follows the :ref:password-hash-api.

It supports a variable-length salt, and a variable number of rounds.

The :meth:~passlib.ifc.PasswordHash.using method accepts the following optional keywords:

Parameters:

  • salt –

    Optional raw salt string. If not specified, one will be autogenerated (this is recommended).

  • salt_size –

    Optional number of bytes to use when autogenerating new salts. Defaults to 16 bytes, but can be any non-negative value.

  • rounds –

    Optional number of rounds to use. Defaults to 480000, must be between 1 and 4294967295, inclusive.

  • variant –

    Optionally specifies variant of FSHP to use.

    • 0 - uses SHA-1 digest (deprecated).
    • 1 - uses SHA-2/256 digest (default).
    • 2 - uses SHA-2/384 digest.
    • 3 - uses SHA-2/512 digest.
  • relaxed (bool) –

    By default, providing an invalid value for one of the other keywords will result in a :exc:ValueError. If relaxed=True, and the error can be corrected, a :exc:~passlib.exc.PasslibHashWarning will be issued instead. Correctable errors include rounds that are too small or too large, and salt strings that are too long.

    .. versionadded:: 1.6

encrypt classmethod

encrypt(*args, **kwds)

Legacy alias for :meth:hash.

.. deprecated:: 1.7 This method was renamed to :meth:!hash in version 1.7. This alias will be removed in version 2.0, and should only be used for compatibility with Passlib 1.3 - 1.6.

parsehash classmethod

parsehash(hash, checksum=True, sanitize=False)

[experimental method] parse hash into dictionary of settings.

this essentially acts as the inverse of :meth:hash: for most cases, if hash = cls.hash(secret, **opts), then cls.parsehash(hash) will return a dict matching the original options (with the extra keyword checksum).

this method may not work correctly for all hashes, and may not be available on some few. its interface may change in future releases, if it's kept around at all.

Parameters:

  • hash –

    hash to parse

  • checksum –

    include checksum keyword? (defaults to True)

  • sanitize –

    mask data for sensitive fields? (defaults to False)

bitsize classmethod

bitsize(rounds=None, vary_rounds=0.1, **kwds)

[experimental method] return info about bitsizes of hash

default_salt_chars

default_salt_chars()

charset used to generate new salt strings (defaults to salt_chars)

Format & Algorithm

All of this scheme's hashes have the format: \{FSHP{variant}|{saltsize}|{rounds}\}{data}. A example hash (of password) is:

`{FSHP1|16|16384}PtoqcGUetmVEy/uR8715TNqKa8+teMF9qZO1lA9lJNUm1EQBLPZ+qPRLeEPHqy6C`
  • {variant} is a decimal integer identifying the version of FSHP; in particular, which cryptographic hash function should be used to calculate the checksum. 1 in the example. (see the class description above for a list of possible values).

  • {saltsize} is a decimal integer identifying the number of bytes in the salt. 16 in the example.

  • {rounds} is a decimal integer identifying the number of rounds to apply when calculating the checksum (see below). 16384 in the example.

  • {data} is a base64-encoded string which, when decoded, contains a salt string of the specified size, followed by the checksum. In the example, the data portion decodes to a salt value (in hexadecimal octets) of:

    3eda2a70651eb66544cbfb91f3bd794c

and a checksum value (in hexadecimal octets) of:

`da8a6bcfad78c17da993b5940f6524d526d444012cf67ea8f44b7843c7ab2e82`

FSHP is basically just a wrapper around PBKDF1: The checksum is calculated using pbkdf1(), passing in the password, the decoded salt string, the number of rounds, and hash function specified by the variant identifier. FSHP has one quirk in that the password is passed in as the pbkdf1 salt, and the salt is passed in as the pbkdf1 password.

Security Issues

  • A minor issue is that FSHP swaps the location the password and salt from what is described in the PBKDF1 standard. This issue is mainly noted in order to dismiss it: while the swap permits an attacker to pre-calculate part of the initial digest, the impact of this is negligible when a large number of rounds is used.

  • Since PBKDF1 is based on repeated composition of a hash, it is vulnerable to any first-preimage attacks on the underlying hash. This has led to the deprecation of using SHA-1 or earlier hashes with PBKDF1. In contrast, its successor PBKDF2 was designed to mitigate this weakness (among other things), and enjoys much stronger preimage resistance when used with the same cryptographic hashes.

Deviations

  • Unicode Policy:

The official FSHP python implementation takes in a password specified as a series of bytes, and does not specify what encoding should be used; though a us-ascii compatible encoding is implied by the implementation, as well as all known reference hashes.

In order to provide support for unicode strings, Passlib will encode unicode passwords using utf-8 before running them through FSHP. If a different encoding is desired by an application, the password should be encoded before handing it to Passlib.


  1. The FSHP homepage contains implementations in a wide variety of programming languages -- https://github.com/bdd/fshp-is-not-secure-anymore ↩

  2. rfc defining PBKDF1 & PBKDF2 - http://tools.ietf.org/html/rfc2898 ↩