Random password generator – Python3
In this guide we will teach you to how create a close to true random password generator in Python.
With data leaks being as common as they are, good password management has become a critical part of your online tasks.
While there are great applications such as Last pass out there already, the benefit of having a simple Python script comes from having complete and total control over what is being executed.
This guide expects you to have Python 3.6.4 or higher. If you need help with installing this please visit the official website here
Without further ado, let’s get right into it!
Setting up your environment
A best practice when getting started with Python is your setting up your virtual environment per project. A virtual environment is a place inside your directories where you can set up all your dependencies and versions which are required by the project you’re working on.
Installing PIP
To install our virtual environment we will need to use a Python’s package manager, PIP
.
To see if PIP installed successfully, open a terminal and type the following
$ pip help
If you see an output from PIP, then it’s installed correctly. If you do not have PIP installed see below on how to install it.
Installing PIP on Windows
If you installed Python on Windows through the installer you should already have PIP installed. If that’s not the case, you can get PIP by running the following command inside a command prompt
python get-pip.py
Installing PIP on Linux
To install PIP on Linux run the following command
$ apt install python3-pip
Installing PIP on openSUSE
To install PIP on openSUSE run the following command
$ zypper install python3-pip
Installing PIP on Arch Linux
To install PIP on Arch Linux run the following command
$ pacman -S python-pip
Installing PIP on CentOS & RHEL
Installing PIP on CentOS & RHEL is a bit different. PIP isn’t packaged into the official software repositories that CentOS & RHEL provide.
First we need to install the EPEL repository, this one provides the PIP package.
$ yum install epel-release
After that we can install PIP
$ yum install python-pip
Installing virtualenv
We’ve installed PIP, so now we can finally install our virtual environment.
We do so by executing the following command
For Windows $ pip install virtualenv For non-Windows $ pip install --user virtualenv
After we’ve installed virtualenv
we can start our Python project. Create a new directory in a location where you want to have your password script, eg. /home/User/RandomPassword/
or on Windows systems, C:\\Users\\Default\\Documents\\RandomPassword
.
Open up a terminal inside that directory and type the following command
$ virtualenv ENV
This will create an ENV
directory inside our RandomPassword
directory. Next, we need to activate our virtual environment. We do so by running the following
$ source ENV/bin/activate
You should see the following inside your command prompt after running the source command
(venv) /path/to/python/project
Notice the (venv)
part? This means we activated our virtual environment. All our dependencies will be installed to the ENV
directory we just created.
Now we can start working on our script!
Creating our random password generator
Let’s get started by creating a new file inside our RandomPassword
directory called pass.py
and open it up in your preferred text editor.
We want our script to do change the output of the password depending on the arguments we give to our script. So let’s start with that
#!/usr/bin/env python # pass.py import argparse from distutils import util def main(): """Setup the parser by adding available arguments""" parser = argparse.ArgumentParser( description="Password Generator", usage="pass.py\npass.py -l 32\npass.py -lc False\npass.py -s False\npass.py [-h] [-l [LENGTH]] [-lc [" "LOWERCASE]] [-uc [UPPERCASE]] [-n [NUMBERS]] [-s [SYMBOLS]]", epilog="Thanks for using!" ) args = parser.parse_args() if __name__ == "__main__": main()
If we run this file right now we see that the script doesn’t do much yet. Running it again with the --help
flag, so: (venv) python pass.py --help
will give us a help message which looks like this
usage: pass.py pass.py -l 32 pass.py -lc False pass.py -s False pass.py [-h] [-l [LENGTH]] [-lc [LOWERCASE]] [-uc [UPPERCASE]] [-n [NUMBERS]] [-s [SYMBOLS]] Password Generator optional arguments: -h, --help show this help message and exit -l [LENGTH], --length [LENGTH] Length of the password. Defaults to 16. Lower is not recommended -lc [LOWERCASE], --lowercase [LOWERCASE] Use lowercase letters during generation. Defaults to True -uc [UPPERCASE], --uppercase [UPPERCASE] Use uppercase letters during generation. Defaults to True -n [NUMBERS], --numbers [NUMBERS] Use numbers during generation. Defaults to True -s [SYMBOLS], --symbols [SYMBOLS] Use symbols during generation. Defaults to True Thanks for using!
Let’s add some arguments that our script can use and assign them to some variable
#!/usr/bin/env python # pass.py import argparse from distutils import util def main(): """Setup the parser by adding available arguments""" parser = argparse.ArgumentParser( description="Password Generator", usage="pass.py\npass.py -l 32\npass.py -lc False\npass.py -s False\npass.py [-h] [-l [LENGTH]] [-lc [" "LOWERCASE]] [-uc [UPPERCASE]] [-n [NUMBERS]] [-s [SYMBOLS]]", epilog="Thanks for using!" ) parser.add_argument("-l", "--length", nargs='?', const=16, type=int, default=16, help="Length of the password. Defaults to 16. Lower is not recommended") parser.add_argument("-lc", "--lowercase", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use lowercase letters during generation. Defaults to True") parser.add_argument("-uc", "--uppercase", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use uppercase letters during generation. Defaults to True") parser.add_argument("-n", "--numbers", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use numbers during generation. Defaults to True") parser.add_argument("-s", "--symbols", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use symbols during generation. Defaults to True") args = parser.parse_args() l = args.length lc = args.lowercase up = args.uppercase n = args.numbers s = args.symbols print(str(l) + "\n") print(str(lc) + "\n") print(str(up) + "\n") print(str(n) + "\n") print(str(s) + "\n") if __name__ == "__main__": main()
If we run our script now we should be greeted with the following output
16 True True True True
Let’s try disabling symbols with (venv) python pass.py -s False
16 True True True False
Cool! Our arguments appear to be working correctly. Now it’s time to generate a password!
#!/usr/bin/env python # pass.py import argparse import secrets import random import string import distutils from distutils import util def r_pass(length, letters): secretsGenerator = secrets.SystemRandom() letters = letters return ''.join(letters[secretsGenerator.randint(0, len(letters) - 1)] for i in range(length)) def main(): """Setup the parser by adding available arguments""" parser = argparse.ArgumentParser( description="Password Generator", usage="pass.py\npass.py -l 32\npass.py -lc False\npass.py -s False\npass.py [-h] [-l [LENGTH]] [-lc [" "LOWERCASE]] [-uc [UPPERCASE]] [-n [NUMBERS]] [-s [SYMBOLS]]", epilog="Thanks for using!" ) parser.add_argument("-l", "--length", nargs='?', const=16, type=int, default=16, help="Length of the password. " "Defaults to 16. Lower is " "not recommended") parser.add_argument("-lc", "--lowercase", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use lowercase letters during generation. Defaults to True") parser.add_argument("-uc", "--uppercase", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use uppercase letters during generation. Defaults to True") parser.add_argument("-n", "--numbers", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use numbers during generation. Defaults to True") parser.add_argument("-s", "--symbols", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use symbols during generation. Defaults to True") args = parser.parse_args() l = args.length lc = args.lowercase up = args.uppercase n = args.numbers s = args.symbols letters = "" letters += string.ascii_lowercase if lc else "" letters += string.ascii_uppercase if up else "" letters += "0123456789" if n else "" letters += "!@#$%^&*()_+-={}[]<>,.;:/~" if s else "" res = r_pass(l, letters) print(res) if __name__ == "__main__": main()
What we’ve done here is add a string of characters called letters
. We append different groups of characters depending on whether the passed argument returns True or False.
We then pass our length argument and our final letters
string to a function called r_pass
. This function does the random generation and noise magic. We use a library called secrets for the noise and randomness.
This function returns a random character from the letters
we provided by passing arguments. It does this until we’ve hit the limit of argument l
length
If we run our code now we should see an output resembling something like
(venv) python pass.py >[H}%}h*_mfAj(j6
That’s all there is to it. You’ve now made your own random password generator!
Optional – Place in clipboard
Want to know how we can make this generator even more fancy? We can make it return our password directly into our computer’s clipboard. We do this by updating our main()
function and by creating another function called module_exists(module_name)
Our final code becomes
#!/usr/bin/env python # pass.py import argparse import secrets import random import string import distutils from distutils import util def r_pass(length, letters): secretsGenerator = secrets.SystemRandom() # letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-={}[]<>,.;:/~" letters = letters # return ''.join(random.choice(letters) for i in range(length)) return ''.join(letters[secretsGenerator.randint(0, len(letters) - 1)] for i in range(length)) def main(): """Setup the parser by adding available arguments""" parser = argparse.ArgumentParser( description="Password Generator", usage="pass.py\npass.py -l 32\npass.py -lc False\npass.py -s False\npass.py [-h] [-l [LENGTH]] [-lc [" "LOWERCASE]] [-uc [UPPERCASE]] [-n [NUMBERS]] [-s [SYMBOLS]]", epilog="Thanks for using!" ) parser.add_argument("-l", "--length", nargs='?', const=16, type=int, default=16, help="Length of the password. Defaults to 16. Lower is not recommended") parser.add_argument("-lc", "--lowercase", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use lowercase letters during generation. Defaults to True") parser.add_argument("-uc", "--uppercase", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use uppercase letters during generation. Defaults to True") parser.add_argument("-n", "--numbers", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use numbers during generation. Defaults to True") parser.add_argument("-s", "--symbols", nargs='?', const=True, type=lambda x: bool(distutils.util.strtobool(x)), default=True, help="Use symbols during generation. Defaults to True") args = parser.parse_args() l = args.length lc = args.lowercase up = args.uppercase n = args.numbers s = args.symbols letters = "" letters += string.ascii_lowercase if lc else "" letters += string.ascii_uppercase if up else "" letters += "0123456789" if n else "" letters += "!@#$%^&*()_+-={}[]<>,.;:/~" if s else "" res = r_pass(l, letters) if module_exists("pyperclip"): pyperclip.copy(res) print("Password has been copied to your clipboard") else: print(res) def module_exists(module_name): try: __import__(module_name) except ImportError: return False else: return True if __name__ == "__main__": main()
What we do now after we’ve generated our password is check whether or not the module pyperclip
exists. If it does we paste our password to the clipboard. If it does not, the script prints the password into the console like before.
2 Comments