Table of Contents
- Introduction
- Prerequisites
- Setup
- Creating the User Interface
- Generating a Secure Password
- Encrypting and Decrypting Passwords
- Storing Passwords Safely
- Summary
Introduction
In this tutorial, we will learn how to build a password manager using Python. We will explore cryptographic techniques and libraries available in Python to generate secure passwords, encrypt and decrypt sensitive information, and store passwords safely.
By the end of this tutorial, you will have a functional password manager that can generate strong passwords, encrypt and decrypt password data, and securely store the passwords.
Prerequisites
To follow along with this tutorial, you should have a basic understanding of Python programming language, including variables, functions, loops, and basic file handling. It is also helpful to have some knowledge of cryptography concepts, although it is not mandatory.
Setup
Before we begin, we need to make sure that Python is installed on our system. You can download and install the latest version of Python from the official Python website.
Additionally, we will be using the cryptography
library, which can be installed via pip. Open your terminal or command prompt and run the following command:
python
pip install cryptography
With Python and the required library installed, we are ready to start building our password manager.
Creating the User Interface
The first step in building our password manager is to create a user-friendly command-line interface. We will use the argparse
module to handle command-line arguments and options.
Create a new file called password_manager.py
and add the following code:
```python
import argparse
def create_password():
pass
def retrieve_password():
pass
def main():
parser = argparse.ArgumentParser(description='Password Manager')
subparsers = parser.add_subparsers(title='subcommands', dest='command')
# Create sub-command
create_parser = subparsers.add_parser('create', help='Create a new password')
create_parser.set_defaults(func=create_password)
# Retrieve sub-command
retrieve_parser = subparsers.add_parser('retrieve', help='Retrieve an existing password')
retrieve_parser.set_defaults(func=retrieve_password)
args = parser.parse_args()
args.func()
if __name__ == '__main__':
main()
``` In the above code, we import the `argparse` module and define three functions: `create_password()`, `retrieve_password()`, and `main()`. The `create_password()` and `retrieve_password()` functions will hold the logic for creating and retrieving passwords, respectively.
We then create an instance of the ArgumentParser
class and add two sub-commands: create
and retrieve
. Each sub-command has its own help message and set of arguments. Finally, we parse the command-line arguments and execute the corresponding function based on the sub-command.
Save the file and open your terminal or command prompt. Navigate to the directory where the password_manager.py
file is saved and run the following command:
python
python password_manager.py --help
You should see the help message along with the available sub-commands. Try running the following commands:
python
python password_manager.py create
python password_manager.py retrieve
You will notice that nothing happens when running the commands at the moment. We will now implement the functionality for creating and retrieving passwords in the next sections.
Generating a Secure Password
To create a strong and secure password, we will use the secrets
module, which is part of the Python standard library. The secrets
module provides functions for generating cryptographically strong random numbers and strings.
Let’s update the create_password()
function to generate a random password:
```python
import string
import secrets
def create_password():
length = 12
characters = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(characters) for _ in range(length))
print(f"Generated Password: {password}")
``` In the above code, we define the `length` of the password (12 characters in this case) and specify the `characters` to choose from. We concatenate the lowercase letters, uppercase letters, digits, and punctuation marks to create a comprehensive character set.
Using a loop, we then select length
number of random characters from the provided character set using secrets.choice()
. The selected characters are then joined together to form the password.
Save the file and try running the following command:
python
python password_manager.py create
You should see a randomly generated password each time you run the command.
Encrypting and Decrypting Passwords
Next, we will implement the encryption and decryption functionalities for securing the passwords. We will use the Fernet
symmetric key encryption algorithm provided by the cryptography
library.
Update the create_password()
and retrieve_password()
functions as follows:
```python
import string
import secrets
from cryptography.fernet import Fernet
def load_key():
key = b'abcdefghijklmnop' # Replace with your own key
return key
def encrypt_password(password, key):
cipher_suite = Fernet(key)
encrypted_password = cipher_suite.encrypt(password.encode())
return encrypted_password
def decrypt_password(encrypted_password, key):
cipher_suite = Fernet(key)
decrypted_password = cipher_suite.decrypt(encrypted_password)
return decrypted_password.decode()
def create_password():
length = 12
characters = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(characters) for _ in range(length))
key = load_key()
encrypted_password = encrypt_password(password, key)
print(f"Generated Password: {password}")
print(f"Encrypted Password: {encrypted_password}")
def retrieve_password():
encrypted_password = b'...' # Replace with an actual encrypted password
key = load_key()
decrypted_password = decrypt_password(encrypted_password, key)
print(f"Decrypted Password: {decrypted_password}")
``` In the above code, we first define a hardcoded `key` in the `load_key()` function. In a real-world scenario, you should generate a randomized key and securely store it. We use the same key for both encryption and decryption.
The encrypt_password()
function takes a plain-text password and the encryption key
as input. It creates a Fernet
cipher object with the key and encrypts the password using the encrypt()
method. The encrypted password is then returned.
Similarly, the decrypt_password()
function takes an encrypted password and the decryption key
as input. It creates a Fernet
cipher object with the key and decrypts the password using the decrypt()
method. The decrypted password is returned as a byte string, which we decode to convert it back to plain text.
In the create_password()
function, we generate a random password as before. We then load the encryption key
, encrypt the password using encrypt_password()
, and print the original and encrypted passwords.
In the retrieve_password()
function, we define a placeholder encrypted_password
. You should replace it with an actual encrypted password in your implementation. We load the encryption key
, decrypt the password using decrypt_password()
, and print the decrypted password.
Save the file and try running the following commands:
python
python password_manager.py create
python password_manager.py retrieve
You should now see your password being encrypted and decrypted properly.
Storing Passwords Safely
To securely store the passwords, we will use a file-based approach where each password entry is stored in a separate file. The file name will be a unique identifier for each password.
Update the create_password()
and retrieve_password()
functions as follows:
```python
import string
import secrets
import os
from cryptography.fernet import Fernet
PASSWORDS_DIR = 'passwords'
def load_key():
key = b'abcdefghijklmnop' # Replace with your own key
return key
def encrypt_password(password, key):
cipher_suite = Fernet(key)
encrypted_password = cipher_suite.encrypt(password.encode())
return encrypted_password
def decrypt_password(encrypted_password, key):
cipher_suite = Fernet(key)
decrypted_password = cipher_suite.decrypt(encrypted_password)
return decrypted_password.decode()
def create_password():
length = 12
characters = string.ascii_letters + string.digits + string.punctuation
password = ''.join(secrets.choice(characters) for _ in range(length))
key = load_key()
encrypted_password = encrypt_password(password, key)
print(f"Generated Password: {password}")
print(f"Encrypted Password: {encrypted_password}")
password_id = secrets.token_hex(8)
password_file = os.path.join(PASSWORDS_DIR, f"{password_id}.txt")
os.makedirs(PASSWORDS_DIR, exist_ok=True)
with open(password_file, 'wb') as file:
file.write(encrypted_password)
print(f"Password saved in {password_file}")
def retrieve_password():
password_id = '...' # Replace with an actual password ID
password_file = os.path.join(PASSWORDS_DIR, f"{password_id}.txt")
key = load_key()
with open(password_file, 'rb') as file:
encrypted_password = file.read()
decrypted_password = decrypt_password(encrypted_password, key)
print(f"Decrypted Password: {decrypted_password}")
``` In the updated code, we define a constant variable `PASSWORDS_DIR` which specifies the directory where the password files will be stored.
In the create_password()
function, after encrypting the password, we generate a unique password_id
using the secrets.token_hex()
function. We then create a password file path by joining the PASSWORDS_DIR
and the password_id
with the .txt
extension.
Next, we create the PASSWORDS_DIR
if it doesn’t already exist using the os.makedirs()
function. Finally, we open the password file in binary write mode and write the encrypted password to the file.
In the retrieve_password()
function, we specify a placeholder password_id
which should be replaced with the actual password ID you want to retrieve. We then open the password file in binary read mode and read the encrypted password. The password is then decrypted and printed on the console.
Save the file and try running the following commands:
python
python password_manager.py create
python password_manager.py retrieve
You should now see the password being saved in a file and retrieved successfully.
Summary
In this tutorial, we learned how to build a password manager using Python. We explored the cryptographic techniques provided by the cryptography
library to generate secure passwords, encrypt and decrypt sensitive information, and store passwords safely.
We started by creating a user-friendly command-line interface using the argparse
module. We then implemented the functionality to generate a secure password using the secrets
module.
Next, we added encryption and decryption functionalities using the Fernet
symmetric key encryption algorithm from the cryptography
library.
Finally, to store the passwords safely, we used a file-based approach where each password entry was stored in a separate file with a unique identifier.
By following this tutorial, you have built a basic password manager that can generate strong passwords, encrypt and decrypt password data, and securely store the passwords. You can further enhance this password manager by adding features like password hashing, user authentication, and a graphical user interface.