passlib.hash.cisco_type7 - Cisco "Type 7" hash¶
Danger
This is not a hash, this is a reversible plaintext encoding. This format can be trivially decoded.
This class implements the "Type 7" password encoding used Cisco IOS. This is not actually a true hash, but a reversible XOR Cipher encoding the plaintext password. Type 7 strings are (and were designed to be) plaintext equivalent; the goal was to protect from "over the shoulder" eavesdropping, and little else. They can be trivially decoded. This class can be used directly as follows:
from passlib.hash import cisco_type7
# encode password
h = cisco_type7.hash("password")
print(h)
# > '044B0A151C36435C0D'
# verify password
print(cisco_type7.verify("password", h))
# > True
print(cisco_type7.verify("letmein", h))
# > False
# to demonstrate this is an encoding, not a real hash,
# this class supports decoding the resulting string:
print(cisco_type7.decode(h))
# > 'password'
Tip
See the generic PasswordHash usage examples.
Note
This implementation should work correctly for most cases, but may not fully implement some edge cases (see Deviations below). Please report any issues encountered.
Interface¶
cisco_type7
¶
cisco_type7(salt=None, **kwds)
This class implements the "Type 7" password encoding used by Cisco IOS,
and follows the :ref:password-hash-api.
It has a simple 4-5 bit salt, but is nonetheless a reversible encoding
instead of a real hash.
The :meth:~passlib.ifc.PasswordHash.using method accepts the following optional keywords:
Parameters:
-
salt(int, default:None) –This may be an optional salt integer drawn from
range(0,16). If omitted, one will be chosen at random. -
relaxed(bool) –By default, providing an invalid value for one of the other keywords will result in a :exc:
ValueError. Ifrelaxed=True, and the error can be corrected, a :exc:~passlib.exc.PasslibHashWarningwill be issued instead. Correctable errors includesaltvalues that are out of range.Note that while this class outputs digests in upper-case hexadecimal, it will accept lower-case as well.
This class also provides the following additional method:
.. automethod:: decode
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)
decode
classmethod
¶
decode(hash, encoding='utf-8')
decode hash, returning original password.
Parameters:
-
hash–encoded password
-
encoding–optional encoding to use (defaults to
UTF-8).
Returns:
-
–
password as unicode
Format & Algorithm¶
The Cisco Type 7 encoding consists of two decimal digits
(encoding the salt), followed a series of hexadecimal characters,
two for every byte in the encoded password.
An example encoding (of "password") is 044B0A151C36435C0D.
This has a salt/offset of 4 (04 in the example),
and encodes password via 4B0A151C36435C0D.
Note
The following description may not be entirely correct with respect to the official algorithm, see the Deviations section for details.
The algorithm is a straightforward XOR Cipher:
-
The algorithm relies on the following
ascii-encoded 53-byte constant:"dsfd;kfoA,.iyewrkldJKDHSUBsgvca69834ncxv9873254k;fg87"
-
A integer salt should be generated from the range 0 .. 15. The first two characters of the encoded string are the zero-padded decimal encoding of the salt.
-
The remaining characters of the encoded string are generated as follows: For each byte in the password (starting with the 0th byte), the
{i}'th byte of the password is encoded as follows:a. let
j=(i + salt) % 53b. XOR the{i}'th byte of the password with the{j}'th byte of the magic constant. c. encode the resulting byte as uppercase hexadecimal, and append to the encoded string.
Deviations¶
This implementation differs from the official one in a few ways. It may be updated as more information becomes available.
- Unicode Policy:
Type 7 encoding is primarily used with ASCII passwords,
how it handles other characters is not known.
In order to provide support for unicode strings, Passlib will encode unicode
passwords using UTF-8 before running them through this algorithm. If a
different encoding is desired by an application, the password should be
encoded before handing it to Passlib.
- Magic Constant:
Other implementations contain a truncated 26-byte constant instead of the 53-byte constant listed above. However, it is likely those implementations were merely incomplete, as they exhibit other issues as well after the 26th byte is reached (throwing an error, truncating the password, outputing garbage), and only worked for shorter passwords.
- Salt Range:
All known test vectors contain salt values in range(0,16).
However, the algorithm itself should be able to handle any salt value
in range(0,53) (the size of the key). For maximum compatibility with
other implementations, Passlib will accept range(0,53), but only
generate salts in range(0,16).
- While this implementation handles all known test vectors, and tries to make sense of the disparate implementations, the actual algorithm has not been published by Cisco, so there may be other unknown deviations.