Skip to content

passlib.hash.cisco_pix - Cisco PIX MD5 hash

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.

Overview

Warning

Caveat Emptor Passlib's implementations of cisco_pix and cisco_asa both need verification. For those with access to Cisco PIX and ASA systems, verifying Passlib's reference vectors would be a great help (see Issue #51). In the mean time, there are no guarantees that passlib correctly replicates the official implementation.

Changed in 1.7.1: A number of bugs were fixed after expanding the reference vectors, and testing against an ASA 9.6 system.

The cisco_asa class implements the "encrypted" password hash algorithm commonly found on Cisco ASA systems. The companion cisco_pix class implements the older variant found on Cisco PIX. Aside from internal differences, and slightly different limitations, the two hashes have the same format, and in some cases the same output.

These classes can be used directly to generate or verify a hash for a specific user. Specifying the user account name is required for this hash:

from passlib.hash import cisco_asa

# hash password using specified username
hash = cisco_asa.hash("password", user="user")
print(hash)
# > 'A5XOy94YKDPXCo7U'

# verify correct password
print(cisco_asa.verify("password", hash, user="user"))
# > True

# verify correct password w/ wrong username
print(cisco_asa.verify("password", hash, user="other"))
# > False

# verify incorrect password
print(cisco_asa.verify("letmein", hash, user="user"))
# > False

The main "enable" password can be hashes / verified just by omitting the user parameter, or setting user="":

# hash password without associated user account
hash2 = cisco_asa.hash("password")
print(hash2)
# > 'NuLKvvWGg.x9HEKO'

# verify password without associated user account
print(cisco_asa.verify("password", hash2))
# > True

Tip

See the generic PasswordHash usage examples.

Interface

cisco_pix

cisco_pix(user=None, **kwds)

This class implements the password hash used by older Cisco PIX firewalls, and follows the :ref:password-hash-api. It does a single round of hashing, and relies on the username as the salt.

This class only allows passwords <= 16 bytes, anything larger will result in a :exc:~passlib.exc.PasswordSizeError if passed to :meth:~cisco_pix.hash, and be silently rejected if passed to :meth:~cisco_pix.verify.

The :meth:~passlib.ifc.PasswordHash.hash, :meth:~passlib.ifc.PasswordHash.genhash, and :meth:~passlib.ifc.PasswordHash.verify methods all support the following extra keyword:

Parameters:

  • user (str, default: None ) –

    String containing name of user account this password is associated with.

    This is *required* in order to correctly hash passwords associated
    with a user account on the Cisco device, as it is used to salt
    the hash.
    
    Conversely, this *must* be omitted or set to ``""`` in order to correctly
    hash passwords which don't have an associated user account
    (such as the "enable" password).
    

    .. versionadded:: 1.6

    .. versionchanged:: 1.7.1

    Passwords > 16 bytes are now rejected / throw error instead of being silently truncated,
    to match Cisco behavior.  A number of :ref:`bugs <passlib-asa96-bug>` were fixed
    which caused prior releases to generate unverifiable hashes in certain cases.
    

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(**kwds)

[experimental method] return info about bitsizes of hash

cisco_asa

cisco_asa(user=None, **kwds)

This class implements the password hash used by Cisco ASA/PIX 7.0 and newer (2005). Aside from a different internal algorithm, it's use and format is identical to the older :class:cisco_pix class.

For passwords less than 13 characters, this should be identical to :class:!cisco_pix, but will generate a different hash for most larger inputs (See the Format & Algorithm_ section for the details).

This class only allows passwords <= 32 bytes, anything larger will result in a :exc:~passlib.exc.PasswordSizeError if passed to :meth:~cisco_asa.hash, and be silently rejected if passed to :meth:~cisco_asa.verify.

.. versionadded:: 1.7

.. versionchanged:: 1.7.1

Passwords > 32 bytes are now rejected / throw error instead of being silently truncated,
to match Cisco behavior.  A number of :ref:`bugs <passlib-asa96-bug>` were fixed
which caused prior releases to generate unverifiable hashes in certain cases.

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(**kwds)

[experimental method] return info about bitsizes of hash

Note

These hash algorithms have a context-sensitive peculiarity. They take in an optional username to salt the hash, but have specific restrictions...

  • The username must be provided in order to correctly hash passwords associated with a user account on the Cisco device.

  • Conversely, the username must not be provided (or must be set to "") in order to correctly hash passwords which don't have an associated user account (such as the "enable" password).

Format & Algorithm

Cisco PIX & ASA hashes consist of a 12 byte digest, encoded as a 16 character HASH64 <passlib.utils.binary.h64>-encoded string. An example hash (of "password", with user "") is "NuLKvvWGg.x9HEKO".

The PIX / ASA digests are calculated as follows:

  1. The password is encoded using UTF-8 (though entering non-ASCII characters is subject to interface-specific issues, and may lead to problems such as double-encoding).

If the result is greater than 16 bytes (for PIX), or 32 bytes (for ASA), the password is not allowed -- it will be rejected when set, and simplify not verify during authentication.

  1. If the hash is associated with a user account, append the first four bytes of the user account name to the end of the password. If the hash is NOT associated with a user account (e.g. it's the "enable" password), this step should be omitted.

If the user account is 1-3 bytes, it is repeated until all 4 bytes are filled up (e.g. "usr" becomes "usru").

For cisco_asa, this step is omitted if the password is 28 bytes or more.

  1. The password+user string is truncated, or right-padded with NULLs, until it's 16 bytes in size.

For cisco_asa, if the password+user string is 16 or more bytes, a padding size of 32 is used instead.

  1. Run the result of step 3 through MD5.

  2. Discard every 4th byte of the 16-byte MD5 hash, starting with the 4th byte.

  3. Encode the 12-byte result using HASH64 <passlib.utils.binary.h64>.

Warning

Changed in 1.7.1: Updated to reflect current understanding of the algorithm.

Security Issues

This algorithm is not suitable for any use besides manipulating existing Cisco PIX hashes, due to the following flaws:

  • Its use of the username as a salt value (and only the first four characters at that), means that common usernames (e.g. admin, cisco) will occur more frequently as salts, weakening the effectiveness of the salt in foiling pre-computed tables.

  • Its truncation of the password+user combination to 16 characters additionally limits the keyspace, and the effectiveness of the username as a salt; making pre-computed and brute force attacks much more feasible.

  • Since the keyspace of password+user is still a subset of ascii characters, existing MD5 lookup tables have an increased chance of being able to reverse common hashes.

  • Its simplicity, and the weakness of MD5, makes high-speed brute force attacks much more feasible.

  • Furthermore, it discards of 1/4 of MD5's already small 16 byte digest, making collisions much more likely.

Deviations

This implementation tries to adhere to the canonical Cisco implementation, but without an official specification, there may be other unknown deviations. The following are known issues:

  • Unicode Policy:

ASA documentation 1 indicates it uses UTF-8 encoding, and Passlib does as well. However, some ASA interfaces have issues such as: ASDM may double-encode unicode characters, and SSH connections may drop non-ASCII characters entirely.

  • How usernames are added is not entirely pinned down. Under ASA, 3-character usernames have their last character repeated to make a string of length 4. It is currently assumed that a similar repetition would be applied to usernames of 1-2 characters, and that this applies to PIX as well; though neither assumption has been confirmed.

  • Passlib 1.7.1 Bugfix: Prior releases of Passlib had a number of issues with their implementation of the PIX & ASA algorithms. As of 1.7.1, the reference vectors were greatly expanded, and then tested against an ASA 9.6 system. This revealed a number of errors in passlib's implementation, which under the following conditions would create hashes that were unverifiable on a Cisco system:

    • PIX and ASA: Usernames containing 1-3 characters were not appended correctly (step 2, above).

    • ASA omits the user entirely (step 2, above) for passwords with >= 28 characters, not >= 27. Non-enable passwords of exactly 27 characters were previous hashed incorrectly.

    • ASA's padding size decision (step 3, above) is made after the user has been appended, not before. This caused prior releases to incorrectly hash non-enable passwords of length 13-15.

Anyone relying on cisco_asa or cisco_pix should upgrade to Passlib 1.7.1 or newer to avoid these issues.

References