Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 53 additions & 37 deletions generator.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
from time import sleep
from secrets import choice
from zxcvbn import zxcvbn
from pandas import DataFrame as DF


class Generator:
def __init__(self):
self.passlist = []
self.results = []
self.df = DF()
self.password_length=0
def _generate_password(self,length):
self.password_length = 0

def _generate_password(self, length):
# Define the character sets to be used in the password generation
alphabets = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM'
symbols = '`1234567890-=[]\\;\',./~!@#$%^&*()_+{}|:"<>?'
Expand All @@ -26,7 +26,7 @@ def _generate_password(self,length):

return ''.join(password)

def _jumble_string(self,string):
def _jumble_string(self, string):
chars = list(string)
jumbled_string = ''
l = len(chars)
Expand All @@ -37,53 +37,68 @@ def _jumble_string(self,string):

return jumbled_string

def generator(self,n,password_length):
def generator(self, n, password_length):
if not isinstance(n, int):
raise TypeError("n must be an integer.")
if not isinstance(password_length, int):
raise TypeError("password_length must be an integer.")
self.__init__()#clearing memory to clear out previously generated suggestions
self.password_length=password_length
self.passlist = [self._generate_password(password_length) for _ in range(n)]
self.strengthEvaluator()
if password_length < 11:
return [] # Return an empty list if the password length is less than 11
self.__init__() # Clear memory to clear out previously generated suggestions
self.password_length = password_length
num_generated = 0 # Counter for the number of generated passwords with score 4
#gap_counter = 0 # Counter to track the gap between successful score 4 generations

while num_generated < n:
password = self._generate_password(password_length)
insights = zxcvbn(password)
if insights['score'] == 4:
self.passlist.append([password,insights['crack_times_seconds']['offline_fast_hashing_1e10_per_second']])
num_generated += 1
gap_counter = 0 # Reset the gap counter since a score 4 password was generated
else:
gap_counter += 1



def strengthEvaluator(self):
"""Accepts a list of passwords and returns insights in the form of list of the passwords and their score
[on a scale of 0 to 4] and respective cracktime estimates at different brute force speeds."""
self.results = []
for i, password in enumerate(self.passlist):
if not isinstance(password, str):
raise ValueError("The Password list must contain string literals")

insights = zxcvbn(password)
self.results.append({
'Sl.No.': i + 1,
'suggested password': password,
'score': insights['score'],
'@100/hr': insights['crack_times_display']['online_throttling_100_per_hour'],
'@36,000/hr': insights['crack_times_display']['online_no_throttling_10_per_second'],
'@196,000/hr': insights['crack_times_display']['offline_slow_hashing_1e4_per_second'],
'@792.9M/hr': insights['crack_times_display']['offline_fast_hashing_1e10_per_second']
})

self.df = DF(self.results)
result_entry = [
i + 1,
password,
insights['score'],
insights['crack_times_seconds']['offline_fast_hashing_1e10_per_second']
]
self.results.append(result_entry)

def get_top_passwords(self, n):
"""returns a subset of the original self.results containing top n suggestions sorted in descending order of strength"""
df = self.df[self.df['score'] == 4]
df = df.sort_values(by='score', ascending=False) # Sort in descending order based on 'score'
top_passwords = df.head(n).to_dict('records') # Convert the top 'n' rows to a list of dictionaries
return top_passwords
"""Returns a subset of the original self.passlist containing the top 'n' suggestions sorted by longest crack times."""
sorted_passwords = sorted(self.passlist, key=lambda p: p[1], reverse=True)
return sorted_passwords[:n]

def display_suggestions(self, n):#displays top n suggestions
# Print the header
if not isinstance(n,int):
raise ValueError("n must be integer type")
print(f'{"Sl.No.":<8} {"suggested password":<{self.password_length+5}} {"score":<10} {"@100/hr":<10} {"@36,000/hr":<10} {"@196,000/hr":<10} {"@792.9M/hr":<10}')



def display_suggestions(self, n):
top = self.get_top_passwords(n)

# Determine the maximum password length in the top suggestions
max_length = max(len(password) for password, _ in top)

# Print the header
print(f'{"Sl.No.":<8} {"suggested password":<{max_length+5}} {"score":<10} {"Vs e^10/sec Hashing[Hrs].":<27}')


# Print the data
for row in top:
print(f'{row["Sl.No."]:<8} {row["suggested password"]:{self.password_length+5}} {row["score"]:<10} {row["@100/hr"]:<10} {row["@36,000/hr"]:<10} {row["@196,000/hr"]:<13} {row["@792.9M/hr"]:<10}')
for i, (password, crack_time) in enumerate(top, start=1):
print(f'{i:<8} {password:<{max_length+5}} {4:<10} {crack_time / 3600:<.4f}')



def main():
"""An example of how this class can be used"""
Expand All @@ -97,7 +112,7 @@ def main():
print('Length must be between 15 and 25. Try again.')
continue
else:
break#if specified length is within hard coded constraints
break # If specified length is within hard-coded constraints
except ValueError:
print('Invalid input. Try again.\n\n')

Expand All @@ -108,7 +123,7 @@ def main():
print('Only values between 1 and 100 (inclusive) are allowed.')
continue
else:
break#if number of suggestions requested is within hard-coded limits
break # If the number of suggestions requested is within hard-coded limits
except ValueError:
print('Invalid input. Try again.\n\n')

Expand All @@ -121,5 +136,6 @@ def main():
sleep(.999)
print(f'\rAutoterminating in {30 - i - 1} seconds', end='', flush=True)


if __name__ == "__main__":
main()