Skip to content

feat: add Cisco type 8, type 9, convoluted type 9 and ASA pbkdf2, and Junos $9$ handlers - #32

Open
ggiesen wants to merge 4 commits into
notypecheck:mainfrom
ggiesen:cisco-type8-type9
Open

ggiesen wants to merge 4 commits into
notypecheck:mainfrom
ggiesen:cisco-type8-type9

Conversation

@ggiesen

@ggiesen ggiesen commented Oct 26, 2026 •

Copy link
Copy Markdown

Adds handlers for Cisco type 8 (PBKDF2-HMAC-SHA256, 20000 rounds) and type 9
(scrypt, N=16384, r=1, p=1) secrets and Cisco ASA "pbkdf2" passwords
(PBKDF2-HMAC-SHA512), which the docs list as unsupported (passlib issue 87,
https://foss.heptapod.net/python-libs/passlib/-/work_items/87), for the
"convoluted type 9" ($14$) secrets IOS XE converts type 5 secrets to, and for
the Junos "$9$" reversible encoding.

Test vectors were generated on a Cisco c8000v running IOS XE 17.15.6, plus
the hashcat example hashes, on an ASAv running 9.24(10), and on
vJunos-router 25.4R1-S2.3. IOS XE hashes only the first 127 bytes of a longer
password, so the type 8 and 9 handlers do the same; truncate_error=True
raises instead.

For $14$, the device's conversions of known type 5 secrets confirm it is
scrypt of the whole md5_crypt string ($1$salt$checksum), as hashcat's mode
38200 has it.

The ASA format is $sha512$<rounds>$<salt>$<checksum>: the first 16 bytes
of PBKDF2-HMAC-SHA512 over a 16 byte salt, both standard base64 with padding.
Unlike cisco_asa, the username isn't hashed in. ASA 9.24 generates 5000
rounds, also accepts other counts (a login against a 10000 round hash made by
this handler succeeded), and refuses passwords longer than 127 bytes, so
hash() raises for those.

Cisco type 9 hashes and Junos secrets both start with "$9$". The two
handlers tell them apart by the second "$" a type 9 hash has, so a
CryptContext can hold both.

Type 8 is PBKDF2-HMAC-SHA256 with 20000 rounds and type 9 is scrypt
with N=16384, r=1, p=1, both with a 14 character salt. Test vectors
were generated on IOS XE 17.15.6, which hashes only the first 127
bytes of a password.
This is the reversible "$9$" encoding Junos uses for secrets such as
RADIUS and TACACS+ keys. Test vectors were generated on vJunos-router
25.4R1-S2.3.

cisco_type9 hashes also start with "$9$", so both handlers identify by
whether a second "$" follows.
@ggiesen ggiesen changed the title feat(cisco): add cisco_type8 and cisco_type9 handlers feat: add cisco_type8, cisco_type9 and junos9 handlers Oct 26, 2026
IOS XE converts a Type 5 secret to "convoluted Type 9" ($14$): scrypt,
as in Type 9, of the whole md5_crypt hash. Test vectors are Type 5
secrets as converted by IOS XE 17.15.6 when configured.
@ggiesen ggiesen changed the title feat: add cisco_type8, cisco_type9 and junos9 handlers feat: add Cisco type 8, type 9 and convoluted type 9, and Junos $9$ handlers Oct 26, 2026
ASA stores a user's plain text password as
"$sha512$<rounds>$<salt>$<checksum>" with the "pbkdf2" keyword: the
first 16 bytes of PBKDF2-HMAC-SHA512 over a 16 byte salt, both in
standard base64 with padding. The username isn't hashed in, unlike
cisco_asa. Test vectors were generated on ASAv 9.24(10), which uses
5000 rounds and refuses passwords longer than 127 bytes.

The docs listed this format as unsupported (passlib issue 87).
@ggiesen ggiesen changed the title feat: add Cisco type 8, type 9 and convoluted type 9, and Junos $9$ handlers feat: add Cisco type 8, type 9, convoluted type 9 and ASA pbkdf2, and Junos $9$ handlers Oct 28, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant