Homework 05: hulk.py

This commit is contained in:
Owen Dorweiler 2025-03-01 16:37:50 -05:00
commit 6d97679d1a

87
homework05/hulk.py Normal file → Executable file
View file

@ -29,9 +29,9 @@ def sha1sum(s: str) -> str:
>>> sha1sum('a')
'86f7e437faa5a7fce15d1ddcb9eaeaea377667b8'
'''
# TODO: Use the hashlib library to produce the SHA1 hex digest of the given
# string.
return ''
hashOfString = hashlib.sha1()
hashOfString.update(s.encode('utf-8'))
return hashOfString.hexdigest()
def permutations(length: int, alphabet: str=ALPHABET) -> Iterator[str]:
''' Recursively yield all permutations of alphabet up to given length.
@ -42,9 +42,12 @@ def permutations(length: int, alphabet: str=ALPHABET) -> Iterator[str]:
ba
bb
'''
# TODO: Use yield to create a generator function that recursively produces
# all the permutations of the given alphabet up to the provided length.
yield ''
if length == 0: # Base case
yield ''
else: # Recursive case
for prefix in alphabet:
for suffix in permutations(length - 1, alphabet):
yield prefix + suffix # this can be done in one line but I think this is more readble
def flatten(sequence: Iterable[Iterable[str]]) -> Iterator[str]:
''' Flatten sequence of iterables.
@ -55,8 +58,10 @@ def flatten(sequence: Iterable[Iterable[str]]) -> Iterator[str]:
c
d
'''
# TODO: Iterate through sequence and yield from each iterator in sequence.
yield ''
for sub_iterable in sequence:
yield from sub_iterable
def crack(hashes: set[str], length: int, alphabet: str=ALPHABET, prefix: str='') -> list[str]:
''' Return all password permutations of specified length that are in hashes
@ -67,10 +72,14 @@ def crack(hashes: set[str], length: int, alphabet: str=ALPHABET, prefix: str='')
b
c
'''
# TODO: Return list comprehension that iterates over a sequence of
# candidate permutations and checks if the sha1sum of each candidate is in
# hashes.
return []
matches = []
for perm in permutations(length, alphabet):
candidate = prefix + perm
if sha1sum(candidate) in hashes:
matches.append(candidate)
return matches
def whack(arguments: tuple[set[str], int, str, str]) -> list[str]:
''' Call the crack function with the specified list of arguments
@ -80,7 +89,8 @@ def whack(arguments: tuple[set[str], int, str, str]) -> list[str]:
b
c
'''
return []
hashes, length, alphabet, prefix = arguments
return crack(hashes, length, alphabet, prefix)
def smash(hashes: set[str], length: int, alphabet: str=ALPHABET, prefix: str='', cores: int=1) -> Iterator[str]:
''' Return all password permutations of specified length that are in hashes
@ -91,9 +101,15 @@ def smash(hashes: set[str], length: int, alphabet: str=ALPHABET, prefix: str='',
b
c
'''
# TODO: Create generator expression with arguments to pass to whack and
# then use ProcessPoolExecutor to apply whack to all items in expression.
yield ''
arguments = ((hashes, length-1, alphabet, prefix + p) for p in alphabet)
# Use the ProcessPoolExecutor to make use of mutliple cores (specified by user)
with concurrent.futures.ProcessPoolExecutor(cores) as executor:
results = executor.map(whack, arguments)
return flatten(results) # return results after flattening them
# Main Execution
@ -112,13 +128,44 @@ def main(arguments: list[str]=sys.argv[1:]) -> None:
length = 1
prefix = ''
# TODO: Parse command line arguments
# Parse command line arguments (I use the same while loop structure as searx.py)
i = 0
while i < len(arguments):
arg = arguments[i]
# TODO: Load hashes set
if arg == '-a':
alphabet = arguments[i+1]
i += 2
elif arg == '-c':
cores = int(arguments[i+1])
i += 2
elif arg == '-l':
length = int(arguments[i+1])
i += 2
elif arg == '-p':
prefix = arguments[i+1]
i += 2
elif arg == '-s':
hashes_path = arguments[i+1]
i += 2
elif arg == '-h':
usage(0)
else:
usage(1)
# TODO: Execute smash function
# Load hashes set
hashes = set()
with open(hashes_path) as hashfile:
for line in hashfile:
hashes.add(line.strip())
# Execute smash function and store results
results = smash(hashes, length, alphabet, prefix, cores)
# Print all found passwords
for password in results:
print(password)
# TODO: Print all found passwords
if __name__ == '__main__':
main()