Skip to content

Commit

Permalink
Merge pull request #6 from superadm1n/master
Browse files Browse the repository at this point in the history
Restructure core functions into Python package
  • Loading branch information
BrettVerney authored Apr 21, 2022
2 parents 0c4524c + df4e6b9 commit 74a52f5
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 107 deletions.
98 changes: 98 additions & 0 deletions CiscoPWDhasher/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import random
import base64
import scrypt
from backports.pbkdf2 import pbkdf2_hmac
from passlib.hash import md5_crypt
from passlib.hash import cisco_type7

# Translate Standard Base64 table to Cisco Base64 Table used in Type8 and TYpe 9
std_b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
cisco_b64chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
b64table = str.maketrans(std_b64chars, cisco_b64chars)


class InvalidPassword(Exception):
"""
Exception to be thrown if an invalid password is submitted to be hashed.
"""
pass


def pwd_check(pwd):
"""
Checks cleartext password for invalid characters
:param pwd: Clear text password
:raises InvalidPassword: If the password contains invalid characters not supported by Cisco
:return: None
"""
invalid_chars = r"?\""
if len(pwd) > 127:
raise InvalidPassword('Password must be between 1 and 127 characters in length.')
if any(char in invalid_chars for char in pwd):
raise InvalidPassword(r'? and \" are invalid characters for Cisco passwords.')


def type5(pwd):
"""
Hashes cleartext password to Cisco type 5
:param pwd: Clear text password to be hashed
:raises InvalidPassword: If the password contains invalid characters not supported by Cisco
:return: Hashed password
"""
pwd_check(pwd)
return md5_crypt.using(salt_size=4).hash(pwd)


def type7(pwd):
"""
Hashes cleartext password to Cisco type 7
:param pwd: Clear text password to be hashed
:raises InvalidPassword: If the password contains invalid characters not supported by Cisco
:return: Hashed password
"""
pwd_check(pwd)
return cisco_type7.hash(pwd)


def type8(pwd):
"""
Hashes cleartext password to Cisco type 8
:param pwd: Clear text password to be hashed
:raises InvalidPassword: If the password contains invalid characters not supported by Cisco
:return: Hashed password
"""
pwd_check(pwd)
salt_chars = []
for _ in range(14):
salt_chars.append(random.choice(cisco_b64chars))
salt = "".join(salt_chars)
# Create the hash
hash = pbkdf2_hmac("sha256", pwd.encode(), salt.encode(), 20000, 32)
# Convert the hash from Standard Base64 to Cisco Base64
hash = base64.b64encode(hash).decode().translate(b64table)[:-1]
# Print the hash in the Cisco IOS CLI format
password_string = f"$8${salt}${hash}"

return password_string


def type9(pwd):
"""
Hashes password to Cisco type 9
:param pwd: Clear text password
:raises InvalidPassword: If the password contains invalid characters not supported by Cisco
:return: Hashed password
"""
pwd_check(pwd)
salt_chars = []
for _ in range(14):
salt_chars.append(random.choice(cisco_b64chars))
salt = "".join(salt_chars)
# Create the hash
hash = scrypt.hash(pwd.encode(), salt.encode(), 16384, 1, 1, 32)
# Convert the hash from Standard Base64 to Cisco Base64
hash = base64.b64encode(hash).decode().translate(b64table)[:-1]
# Print the hash in the Cisco IOS CLI format
password_string = f'$9${salt}${hash}'
return password_string

Binary file not shown.
138 changes: 34 additions & 104 deletions ciscopwdhasher.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
# Script by Brett Verney (@wifiwizardofoz)
# Contributors - Josh Schmelzle (@joshschmelzle)
# Contributors - Josh Schmelzle (@joshschmelzle), Kyle Kowalczyk(@superadm1n)
# Version: v0.1 | 6-04-2021

import sys
import os
import random
import base64
import scrypt
from backports.pbkdf2 import pbkdf2_hmac
from passlib.hash import md5_crypt
from passlib.hash import cisco_type7
from CiscoPWDhasher import pwd_check, InvalidPassword, type5, type7, type8, type9


# Translate Standard Base64 table to Cisco Base64 Table used in Type8 and TYpe 9
std_b64chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
cisco_b64chars = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
b64table = str.maketrans(std_b64chars, cisco_b64chars)

def banner():
print(r'''
Expand Down Expand Up @@ -43,119 +34,58 @@ def show_menu():
print('[4] Type 9 (Scrypt)')
print('[5] Exit')

def app_start():
def app_start():
"""
Home screen of the script. Gathers input from user to specify what type of hash they want,
collect the cleartext password, hash that cleartext password, and print out the hash to the user.
:return: None
"""
show_menu()
try:
choice = int(input('\n' + 'Your selection: '))
except ValueError:
print ('\n' + 'Invalid option. Please enter 1-5 or press CTRL+C to exit: ' + '\n')
print('\n' + 'Invalid option. Please enter 1-5 or press CTRL+C to exit: ' + '\n')
app_start()
except KeyboardInterrupt:
sys.exit(0)
else:
if choice == 1:
type5()
cleartext_password = pwd_input()
hash = type5(cleartext_password)
print(f'Your Cisco type 5 password is: {hash}')
elif choice == 2:
type7()
cleartext_password = pwd_input()
hash = type7(cleartext_password)
print(f'Your Cisco type 7 password is: {hash}')
elif choice == 3:
type8()
cleartext_password = pwd_input()
hash = type8(cleartext_password)
print(f'Your Cisco type 7 password is: {hash}')
elif choice == 4:
type9()
cleartext_password = pwd_input()
hash = type9(cleartext_password)
print(f'Your Cisco type 9 password is: {hash}')
elif choice == 5:
sys.exit()
else:
print ('\n' + 'Invalid option. Please enter 1-5 or press CTRL + C to exit: ' + '\n')
print('\n' + 'Invalid option. Please enter 1-5 or press CTRL + C to exit: ' + '\n')
app_start()

def pwd_input():
pwd = input('\n' + 'Enter a Plain Text Password to convert: ')
return pwd

def pwd_check(pwd):
invalid_chars = r"?\""
val = True
if len(pwd) > 127:
print('Password must be between 1 and 127 characters in length. Please try again or press CTRL + C to exit:')
val = False
if any(char in invalid_chars for char in pwd):
print('? and \" are invalid characters for Cisco passwords. Please try again or press CTRL + C to exit:')
val = False
if val:
return val

def type5():
valid_pwd = False
while not valid_pwd:
try:
pwd = pwd_input()
except KeyboardInterrupt:
sys.exit(0)
else:
if (pwd_check(pwd)):
# Create the hash
hash = md5_crypt.using(salt_size=4).hash(pwd)
# Print the hash in Cisco Syntax
print( '\n' + f"Your Cisco Type 5 password hash is: {hash}")
valid_pwd = True

def type7():
valid_pwd = False
while not valid_pwd:
"""
Function to gather the input from the user until they enter a valid string that Cisco can use as a password
:return: Password to be hashed
"""
while True:
pwd = input('\n' + 'Enter a Plain Text Password to convert: ')
try:
pwd = pwd_input()
pwd_check(pwd)
return pwd
except InvalidPassword as exception_string:
print(f'{exception_string} Please try again or press CTRL + C to exit: ')
except KeyboardInterrupt:
sys.exit(0)
else:
if (pwd_check(pwd)):
# Create the hash
hash = cisco_type7.hash(pwd)
# Print the hash in Cisco syntax
print( '\n' + f"Your Cisco Type 7 password hash is: {hash}")
valid_pwd = True
exit()

def type8():
valid_pwd = False
while not valid_pwd:
try:
pwd = pwd_input()
except KeyboardInterrupt:
sys.exit(0)
else:
if (pwd_check(pwd)):
# Create random salt (Cisco use 14 characters from custom B64 table)
salt_chars=[]
for _ in range(14):
salt_chars.append(random.choice(cisco_b64chars))
salt = "".join(salt_chars)
# Create the hash
hash = pbkdf2_hmac("sha256", pwd.encode(), salt.encode(), 20000, 32)
# Convert the hash from Standard Base64 to Cisco Base64
hash = base64.b64encode(hash).decode().translate(b64table)[:-1]
# Print the hash in the Cisco IOS CLI format
print( '\n' + f"Your Cisco Type 8 password hash is: $8${salt}${hash}")
valid_pwd = True

def type9():
valid_pwd = False
while not valid_pwd:
try:
pwd = pwd_input()
except KeyboardInterrupt:
sys.exit(0)
else:
if (pwd_check(pwd)):
# Create random salt (Cisco use 14 characters from custom B64 table)
salt_chars=[]
for _ in range(14):
salt_chars.append(random.choice(cisco_b64chars))
salt = "".join(salt_chars)
# Create the hash
hash = scrypt.hash(pwd.encode(), salt.encode(), 16384, 1, 1, 32)
# Convert the hash from Standard Base64 to Cisco Base64
hash = base64.b64encode(hash).decode().translate(b64table)[:-1]
# Print the hash in the Cisco IOS CLI format
print( '\n' + f"Your Cisco Type 9 password hash is: $9${salt}${hash}")
valid_pwd = True

def main():
banner()
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
scrypt==0.8.17
backports.pbkdf2==0.1
passlib==1.7.4
scrypt>=0.8.17
backports.pbkdf2>=0.1
passlib>=1.7.4

0 comments on commit 74a52f5

Please sign in to comment.