1 Strong Password Generator Final Report: Strong Password Generator CYB 333 – Security Automation GitHub: https://github.com/marissabarry/cyb333/ 2 Strong Password Generator Final Report: Strong Password Generator Utilizing strong passwords may be one of the most overlooked security vulnerabilities within any organization. A strong password is defined as a password that contains at least 8 characters, a mixture of both uppercase and lowercase letters, and a mixture of numbers and special characters (ITS, 2019). According to a blog about NIST password standards, a great way to maximize security is to also create password expirations, set a password history and to ensure passwords saved are safeguarded or encrypted (Poza, 2021). With all these requirements in any industry typical users tend to struggle to follow strong password setup rules and proper safeguarding of a password. In a Wall Street Journal article, it states, “The problem, we realized, was that strong passwords are simply too costly. They take longer to type and are harder to memorize. This means that people have no incentive to choose a strong password because we are all, by nature, cognitive misers: People will always choose the path of least resistance.” (Renaud, 2019). Therefore there is incentive to create a script that simplifies the password creation process for users and add a security component. Our team decided that for our Final Project for CYB 333 – Security Automation class that it would be beneficial and fun to create a Python script to help users obtain a strong password and have the option and ability to save the output as an encrypted file for future reference. Below is our final code, which can also be found on GitHub: #!/usr/bin/env python3 #Password Generation Utility #CYB333 Final Project #Marissa Barry et. al. #Generates a user-inputted number of passwords of user-inputted length utilizing a selection of random ASCII characters #Imports; using string for easy access to lists of ASCII characters and random for the randomization 3 Strong Password Generator import random, string #Defining some global variables inputSamples = 0 inputLength = 0 cont = False genPass = [] #Function definitions #Polls user for input, returns boolean; used in a loop for input handling #Uses inputSamples as a global for simplicity def getSamplesNum(): try: global inputSamples inputSamples = int(input('Generate how many passwords? ')) return True except ValueError: print('Invalid input, please try again.') return False #Same idea as getSamplesNum but for length def getSamplesLength(): try: global inputLength inputLength = int(input('Desired password length (min 8 recommended): ')) return True except ValueError: print('Invalid input, please try again.') return False #Returns a randomly generated password of the desired length def passGen(): pword = '' for j in range(inputLength): pword += random.choice(asciiAll) return pword #Gets called after generation to parse user input for writing to a file def userYN(): check = str(input('Save output to a file? (Y/N): ')).lower().strip() try: if check[0] == 'y': return True elif check[0] == 'n': return False else: print('Invalid entry') return userYN() except Exception as error: print('Enter a valid input') print(error) return userYN() #Main menu: prompt user to select choice print('CYB333 Password Generator') 4 Strong Password Generator #Get number of samples to generate using earlier functions #Use of global variables earlier makes this far simpler while cont is False: cont = getSamplesNum() #Get length of samples to generate cont = False while cont is False: cont = getSamplesLength() #Now we know how many passwords to generate and how long they should be, let's get to it print('\nGenerating',inputSamples,'passwords with',inputLength,'characters...') #Establish a base character set to pull from asciiLow = string.ascii_lowercase asciiUp = string.ascii_uppercase asciiNum = string.digits asciiSym = string.punctuation asciiAll = asciiLow + asciiUp + asciiNum + asciiSym #Loop to iterate through the length of the password #Adds each newely generated password to the list defined at the beginning for i in range(inputSamples): pword = passGen() #for j in range(inputLength): # pword += random.choice(asciiAll) if pword in genPass: print('Generated a duplicate, regenerating!') pword = passGen() genPass.insert(i,pword) #Printing newly generated passwords print('\nGenerated',inputSamples,'passwords:\n') for i in genPass: print(i) print('\n') #Bad passwords are EVERYWHERE so let's make sure that none of the generated ones are bad #Using the top 10000 most common passwords from the OWASP SecList Project in a text file, one per line #Using the passwords.txt file to read the list into a list #Create list of common passwords from file bank = open('passwords.txt', 'r') parse = [] for i in bank: words = i.split() for a in words: parse.append(a) #Check generated passwords against list, once again using a boolean/for setup #Testing this is tricky because the generator is too random and hasn't turned up any duplicates yet. #Even on massive test sets (500K,1M) it doesn't find a match but just in case 5 Strong Password Generator print('Checking generated passwords against list of common passwords...') present = False for i in genPass: if i in parse: print(genpass[i],'is on the list of commonly used passwords, recommend not using and regenerating as needed.') present = True if present is False: print('No matches found!') #Close the wordbank file since we're done with it bank.close() #Prompts the user if they want to save the list of passwords to a file #If so, creates the file output.txt and dumps the passwords into it, one per line if userYN() is True: print('\nWriting passwords to output.txt') print('\nCaution: passwords should not be stored in this file once used owing to a lack of encryption') output = open('output.txt','w') for i in genPass: fOut = i + '\n' output.write(fOut) output.close() print('Successfully wrote',inputSamples,'passwords to output.txt') This code was developed with both user and security compliance in mind. The code prompts the user to input how many passwords are required to be generated and the desired password length. We researched the top 1000 passwords commonly used and found the passwords.txt file and incorporated it into our code by using genPass (Miessler, 2019). When a random password is generated and it is not on the list, the script self-corrects with a different output. The ascii() portion of our code was developed to ensure the output password contains an uppercase letter, a lowercase letter, a number and a symbol incorporated together. To thoroughly test and validate our code we wrote and tested each module for functionality as we added the content. By testing our code in the development stages it helped identify portions that needed fixing before moving on to add to the functionality of our code. We also tested a variety of ranges of passwords requesting to be created and a large range of characters required for a password to ensure the code processed error free and without freezing due to large requested outputs. 6 Strong Password Generator When developing our code, our biggest roadblocks were mainly choosing the right inputs to ensure our code looked as clean as it could, flowed appropriately, did not crash or freeze when in use and gave the results we specified correctly and in a timely manner. Through this process of improvement, we all learned more about global variables. Global variables are used throughout our program to ensure continuity. For example, in our script, the global variable we use is so that the variable outside of our function can be called. We used the global function to make it possible to ask for the input of the length and how many passwords needed to be generated. The final component that we added was encryption to the generated password text file. As a security feature, encryption is a vital component. Without our encryption piece, password files would just be saved in clear text and available for anyone to see. Since real world users and by password security standards, all passwords users make for everything they need to sign into should be different from each other and unique so often it is very hard to keep track of, memorize and safeguard. Saving the password into an encrypted file adds a layer of protection to the common user. Screenshots of code testing: The following 3 screenshots show our team testing the outputs desired by using a variety of number ranges. It also shows the passwords going through the password.txt file being tested so that if the passwords from our generator gave an output that was on the 1000 commonly used passwords list it would run through our code and output a different password. It also shows, once the password generated is confirmed to be unique and not on the password.txt file, if our user chooses to save as a file (in clear text). We then decided to take our program a step further to add encryption by ___. *needs screenshot of encryption working. 7 Strong Password Generator 8 Strong Password Generator The screenshot below shows our code being successfully uploaded to a GitHub repository. 9 Strong Password Generator References GeeksforGeeks. (2021, March 1). Global and Local Variables in Python. https://www.geeksforgeeks.org/global-local-variables-python/ ITS. (2019). Guidelines for Strong Passwords. Information Technology Services Guidelines for Strong Passwords Comments. https://its.lafayette.edu/policies/strongpasswords/ Miessler, D. (2019, January 7). danielmiessler/SecLists. GitHub. https://github.com/danielmiessler/SecLists/tree/master/Passwords/Common-Credentials Poza, D. (2021, January 22). NIST Password Guidelines and Best Practices for 2020. Auth0. https://auth0.com/blog/dont-pass-on-the-new-nist-password-guidelines/ Python - Global Variables. (1999). W3 Schools. https://www.w3schools.com/python/python_variables_global.asp Renaud, K. (2019, September 17). People Need an Incentive to Use Strong Passwords. We Gave Them One. WSJ. https://www.wsj.com/articles/people-need-an-incentive-to-use-strongpasswords-we-gave-them-one-11568734702