Skip to content

passlib.hash.md5_crypt - MD5 Crypt

Danger

This algorithm is not considered secure by modern standards. It should only be used when verifying existing hashes, or when interacting with applications that require this format. For new code, see the list of recommended hashes.

This algorithm was developed for FreeBSD in 1994 by Poul-Henning Kamp, to replace the aging passlib.hash.des_crypt. It has since been adopted by a wide variety of other Unix flavors, and is found in many other contexts as well. Due to its origins, it's sometimes referred to as "FreeBSD MD5 Crypt". Security-wise it should now be considered weak, and most Unix flavors have since replaced it with stronger schemes (such as passlib.hash.sha512_crypt and passlib.hash.bcrypt).

This is also referred to on Cisco IOS systems as a "type 5" hash. The format and algorithm are identical, though Cisco seems to require 4 salt characters instead of the full 8 characters used by most systems 3.

The md5_crypt class can be used directly as follows:

from passlib.hash import md5_crypt

# generate new salt, hash password
h = md5_crypt.hash("password")
print(h)
# > '$1$3azHgidD$SrJPt7B.9rekpmwJwtON31'

# verify the password
print(md5_crypt.verify("password", h))
# > True
print(md5_crypt.verify("secret", h))
# > False

# hash password using cisco-compatible 4-char salt
hashed = md5_crypt.using(salt_size=4).hash("password")
print(hashed)
# > '$1$wu98$9UuD3hvrwehnqyF1D548N0'

Tip

Interface

md5_crypt

md5_crypt(salt=None, **kwds)

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

It supports a variable-length salt.

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

Parameters:

  • salt (str, default: None ) –

    Optional salt string. If not specified, one will be autogenerated (this is recommended). If specified, it must be 0-8 characters, drawn from the regexp range [./0-9A-Za-z].

  • salt_size (int) –

    Optional number of characters to use when autogenerating new salts. Defaults to 8, but can be any value between 0 and 8. (This is mainly needed when generating Cisco-compatible hashes, which require salt_size=4).

  • 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 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(salt_size=None, **kwds)

[experimental method] return info about bitsizes of hash

default_salt_size

default_salt_size()

default salt size (defaults to max_salt_size)

default_salt_chars

default_salt_chars()

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

get_backend classmethod

get_backend()

Return name of currently active backend. if no backend has been loaded, loads and returns name of default backend.

Returns:

  • –

    name of active backend

Raises:

  • passlib.exc.MissingBackendError –

    if no backends are available.

has_backend classmethod

has_backend(name='any')

Check if support is currently available for specified backend.

Parameters:

  • name –

    name of backend to check for. can be any string accepted by :meth:set_backend.

Returns:

  • –
    • True if backend is available.
    • False if it's available / can't be loaded.
    • None if it's present, but won't load due to a security issue.

Raises:

  • ValueError –

    if backend name is unknown

set_backend classmethod

set_backend(name='any', dryrun=False)

Load specified backend.

Parameters:

  • name –

    name of backend to load, can be any of the following:

    • "any" -- use current backend if one is loaded, otherwise load the first available backend.

    • "default" -- use the first available backend.

    • any string in :attr:backends, loads specified backend.

  • dryrun –

    If True, this perform all setup actions except switching over to the new backend. (this flag is used to implement :meth:has_backend).

    .. versionadded:: 1.7

Raises:

  • ValueError –

    If backend name is unknown.

  • passlib.exc.MissingBackendError –

    If specific backend is missing; or in the case of "any" / "default", if no backends are available.

  • passlib.exc.PasslibSecurityError –

    If "any" or "default" was specified, but the only backend available has a PasslibSecurityError.

Note

This class will use the first available of two possible backends:

  • stdlib crypt(), if the host OS supports MD5-Crypt (most Unix systems).
  • a pure python implementation of MD5-Crypt built into Passlib.

You can see which backend is in use by calling the get_backend() method.

Format

An example md5-crypt hash (of the string password) is $1$5pZSV9va$azfrPr6af3Fc7dLblQXVa0.

An md5-crypt hash string has the format $1${salt}${checksum}, where:

  • $1$ is the prefix used to identify md5-crypt hashes, following the modular crypt format
  • {salt} is 0-8 characters drawn from the regexp range [./0-9A-Za-z]; providing a 48-bit salt (5pZSV9va in the example).
  • {checksum} is 22 characters drawn from the same character set as the salt; encoding a 128-bit checksum (azfrPr6af3Fc7dLblQXVa0 in the example).

Algorithm

The MD5-Crypt algorithm 1 calculates a checksum as follows:

  1. A password string and salt string are provided.

(The salt should not include the magic prefix, it should match the string referred to as {salt} in the format section, above).

  1. If needed, the salt should be truncated to a maximum of 8 characters.

  2. Start MD5 digest B.

  3. Add the password to digest B.

  4. Add the salt to digest B.

  5. Add the password to digest B.

  6. Finish MD5 digest B.

  7. Start MD5 digest A.

  8. Add the password to digest A.

  9. Add the constant string $1$ to digest A. (The Apache variant of MD5-Crypt uses $apr1$ instead, this is the only change made by this variant).

  10. Add the salt to digest A.

  11. For each block of 16 bytes in the password string, add digest B to digest A.

  12. For the remaining N bytes of the password string, add the first N bytes of digest B to digest A.

  13. For each bit in the binary representation of the length of the password string; starting with the lowest value bit, up to and including the largest-valued bit that is set to 1:

    a. If the current bit is set 1, add the first character of the password to digest A. b. Otherwise, add a NULL character to digest A.

    (If the password is the empty string, step 14 is omitted entirely).

  14. Finish MD5 digest A.

  15. For 1000 rounds (round values 0..999 inclusive), perform the following steps:

    a. Start MD5 Digest C for the round. b. If the round is odd, add the password to digest C. c. If the round is even, add the previous round's result to digest C (for round 0, add digest A instead). d. If the round is not a multiple of 3, add the salt to digest C. e. If the round is not a multiple of 7, add the password to digest C. f. If the round is even, add the password to digest C. g. If the round is odd, add the previous round's result to digest C (for round 0, add digest A instead). h. Use the final value of MD5 digest C as the result for this round.

  16. Transpose the 16 bytes of the final round's result in the following order: 12,6,0,13,7,1,14,8,2,15,9,3,5,10,4,11.

  17. Encode the resulting 16 byte string into a 22 character hash64 <passlib.utils.binary.h64>-encoded string (the 2 msb bits encoded by the last hash64 character are used as 0 padding). This results in the portion of the md5 crypt hash string referred to as {checksum} in the format section.

Security Issues

MD5-Crypt has a couple of issues which have weakened severely:

  • It relies on the MD5 message digest, for which theoretical pre-image attacks exist 2.

  • More seriously, its fixed number of rounds (combined with the availability of high-throughput MD5 implementations) means this algorithm is increasingly vulnerable to brute force attacks. It is this issue which has motivated its replacement by new algorithms such as passlib.hash.bcrypt and passlib.hash.sha512_crypt.

Deviations

Passlib's implementation of md5-crypt differs from the reference implementation (and others) in two ways:

  • Restricted salt string character set:

The underlying algorithm can unambiguously handle salt strings which contain any possible byte value besides \x00 and $``. However, Passlib strictly limits salts to thehash64 ` character set, as nearly all implementations of md5-crypt generate and expect salts containing those characters, but may have unexpected behaviors for other character values.

  • Unicode Policy:

The underlying algorithm takes in a password specified as a series of non-null bytes, and does not specify what encoding should be used; though a us-ascii compatible encoding is implied by nearly all implementations of md5-crypt 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 md5-crypt. If a different encoding is desired by an application, the password should be encoded before handing it to Passlib.


  1. The authoritative reference for MD5-Crypt is Poul-Henning Kamp's original FreeBSD implementation - http://www.freebsd.org/cgi/cvsweb.cgi/~checkout~/src/lib/libcrypt/crypt.c?rev=1.2 ↩

  2. Security issues with MD5 - http://en.wikipedia.org/wiki/MD5#Security. ↩

  3. Note about Cisco Type 5 salt size - http://serverfault.com/a/46399. ↩