Skip to content
Merged
Show file tree
Hide file tree
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
2 changes: 2 additions & 0 deletions Secure_Password_Manager/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
saved_passwords.txt
secret.key
114 changes: 114 additions & 0 deletions Secure_Password_Manager/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# πŸ” Secure Password Manager (CLI + GUI)

This is a simple and secure Password Manager built with Python. It includes both a **Tkinter-based GUI (Graphical User Interface)** and a **CLI (Command Line Interface)** version.

---

## πŸ“Œ Features

* βœ… Generate strong, random passwords
* βœ… Choose what characters to include (lowercase, uppercase, digits, special characters)
* βœ… Real-time password strength feedback
* βœ… Save passwords with labels (e.g., Gmail, Netflix)
* βœ… Encode/Encrypt passwords for security
* βœ… View saved passwords with automatic decryption
* βœ… GUI built using Python's `tkinter` library
* βœ… CLI version with command-line options using `argparse`

---

## πŸ’‘ How It Works

### Tkinter GUI

The graphical interface is built using `tkinter`, Python’s standard GUI toolkit. It provides a clean interface for generating, encrypting, and viewing passwords.

### Generate Password

1. Choose the password length.
2. Select character types using checkboxes.
3. Hit the **Generate Password** button.
4. The password is displayed with its strength (Weak, Medium, or Strong).
5. The password is then **encrypted** and saved to a file.

### View Saved Passwords

1. Click the **View Saved Passwords** button in the GUI.
2. If the encryption key exists, the program decrypts and displays all saved passwords in a pop-up window.
3. If the key is missing or corrupted, an error message is shown.

---

## πŸ› οΈ Technologies Used

| Component | Tool/Library |
|----------|--------------|
| Programming Language | Python |
| GUI Library | Tkinter |
| Encryption | cryptography (Fernet) |
| Encoding (CLI version) | base64 |
| CLI Parser | argparse |
| Version Control | Git |

---

## πŸ—ƒοΈ Project Structure

```bash
Password_Manager/
β”œβ”€β”€ password_manager_gui.py # Tkinter-based GUI application
β”œβ”€β”€ password_manager_cli.py # CLI-based password generator
β”œβ”€β”€ view_passwords_cli.py # View decoded Base64 passwords (CLI)
β”œβ”€β”€ decrypt_passwords_cli.py # Decrypt encrypted passwords (CLI)
β”œβ”€β”€ saved_passwords.txt # File where encrypted passwords are saved
β”œβ”€β”€ secret.key # File containing Fernet encryption key
β”œβ”€β”€ README.md
└── .gitignore
```

---

## ⚠️ Security Note

This project uses **Fernet encryption** to protect your saved passwords.

Files like `secret.key` and `saved_passwords.txt` are excluded from version control using `.gitignore`.

> Do not share your `secret.key` with anyone. If you lose it, saved passwords cannot be decrypted.

---

## 🧠 Ideal For

- Python beginners learning `tkinter`
- Students building secure Python projects
- Learning encryption basics with `cryptography`
- Practicing Git and GitHub workflow with versioned features

---

## βš™οΈ Setup Instructions

1. Clone the repo
`git clone https://github.com/Your-Username/Secure_Password_Manager.git`

2. Install dependencies
`pip install cryptography`

3. Run GUI
`python password_manager_gui.py`

4. Or use CLI
`python password_manager_cli.py --length 12 --label Gmail --lower --upper --digits --specials`

---

## ⭐ GitHub Ready

This project was built using proper Git practices:

* Every feature added on a new branch
* Meaningful commit messages
* Clean merge history

---
63 changes: 63 additions & 0 deletions Secure_Password_Manager/cli/decrypt_passwords_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from cryptography import fernet
import os

KEY_FILE = "secret.key"
PASSWORD_FILE = "saved_passwords.txt"

# STEP 1: Load the encryption key
def load_key():
if not os.path.exists(KEY_FILE):
print("❌ Encryption key not found. Cannot decrypt passwords.")
return None
with open(KEY_FILE, "rb") as f:
return f.read()

# STEP 2: Decrypt the passwords
def decrypt_password(encrypted_text, fernet_cipher_suite): # Renamed parameter for clarity
try:
return fernet_cipher_suite.decrypt(encrypted_text.encode()).decode()
except Exception:
return "[Decryption Failed]"

# STEP 3: Read and decrypt all entries
def view_passwords():
if not os.path.exists(PASSWORD_FILE):
print("❌ No saved passwords found")
return

key = load_key()
if not key:
return

# Fernet = fernet(key) # Original line causing TypeError
active_fernet_cipher = fernet.Fernet(key) # Correctly instantiate Fernet class from the module

print("πŸ” Saved Encrypted Passwords\n" + "=" * 40)
with open(PASSWORD_FILE, "r") as file:
lines = file.readlines()

current_block = {}

for line in lines:
line = line.strip()

if line.startswith("[") and "]" in line:
current_block["timestamp"] = line.strip("[]")
elif line.startswith("Label:"):
current_block["label"] = line.split("Label:")[1].strip()
elif line.startswith("Encrypted Password:"):
current_block["encrypted"] = line.split("Encrypted Password:")[1].strip()
elif line.startswith("Included -"):
current_block["options"] = line.split("Included -")[1].strip()
elif line.startswith("-" * 10):
# print everything together
print(f"\nπŸ“… Date/Time: {current_block.get('timestamp', '[Unknown]')}")
print(f"🏷️ Label: {current_block.get('label', '[None]')}")
print(f"πŸ”“ Password: {decrypt_password(current_block.get('encrypted', ''), active_fernet_cipher)}") # Pass the Fernet instance
print(f"βš™οΈ Options: {current_block.get('options', '[Not specified]')}")
print("-" * 40)
current_block = {} # Reset for next block

# STEP 4: Entry point
if __name__ == '__main__':
view_passwords()
114 changes: 114 additions & 0 deletions Secure_Password_Manager/cli/password_manager_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import random, datetime, base64, argparse, os
from cryptography.fernet import Fernet

# πŸ”‘ File where secret key will be stored
KEY_FILE = "secret.key"

# ------------------------------------------------------
# STEP 1: Generate a new encryption key (only once))
def generate_key():
key = Fernet.generate_key()
with open(KEY_FILE, "wb") as f:
f.write(key)

# STEP 2: Load the ecryption key
def load_key():
if not os.path.exists(KEY_FILE):
print("No Key found. Creating a new one...")
generate_key()
with open(KEY_FILE, "rb") as f:
return f.read()

# STEP 3: Generate password based on user settings
def generate_password(length, use_lower, use_upper, use_digits, use_specials):
lowercase = 'abcdefghijklmnopqrstuvwxyz'
uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
digits = '0123456789'
specials = '!@#$%^&*()'

# Build character set based on user input
character_set = ''

if use_lower:
character_set = character_set + lowercase
if use_upper:
character_set = character_set + uppercase
if use_digits:
character_set = character_set + digits
if use_specials:
character_set = character_set + specials

if not character_set:
return "Error: No character sets selected. Cannot generate password."

password = ''
for i in range(length):
password = password + random.choice(character_set)
return password

# STEP 4: Check password strength
def check_strength(length, use_lower, use_upper, use_digits, use_specials):
score = 0

# Add points for character variety
score = score + use_lower + use_upper + use_digits + use_specials

if length >= 12:
score = score + 1

if score <= 2:
return "Weak"
elif score == 3 or score == 4:
return "Medium"
else:
return "Strong"

# STEP 5: Command-line interface using argparse
def main():
parser = argparse.ArgumentParser(description="πŸ” Password Generator Tool")

parser.add_argument('--length', type=int, required=True, help='Password length (e.g., 8, 12, 16)')
parser.add_argument('--label', type=str, required=True, help='Purpose or label for the password (e.g, Google, Gmail)')
parser.add_argument('--lower', action='store_true', help='Include lowercase letters')
parser.add_argument('--upper', action='store_true', help='Include uppercase letters')
parser.add_argument('--digits', action='store_true', help='Include digits')
parser.add_argument('--specials', action='store_true', help='Include special characters')

args = parser.parse_args()

# Validate length
if args.length <= 0:
print("❌ Password length must be positive. Try again.")
return

# Generate and evaluate password
password = generate_password(args.length, args.lower, args.upper, args.digits, args.specials)
if password.startswith("Error"):
print(password)
return

print(f"βœ… Your generated password is: {password}")
strength = check_strength(args.length, args.lower, args.upper, args.digits, args.specials)
print(f"πŸ’ͺ Password Strenght: {strength}")

# STEP 6: Encrypt password using Fernet
key = load_key()
fernet = Fernet(key)
encrypted_password = fernet.encrypt(password.encode()).decode() # This variable already holds the Fernet encrypted string.

# STEP 7: Save encrypted password to file
with open("saved_passwords.txt", "a") as file:
timestamp = datetime.datetime.now().strftime("%d-%m-%Y %H:%M:%S")
# The 'encoded_password' (base64 of original password) was being saved previously.
# We should save the 'encrypted_password' (Fernet encrypted string) instead.
file.write(f"\n[{timestamp}]\n")
file.write(f"Label: {args.label}\n")
file.write(f"Encrypted Password: {encrypted_password}\n") # Save the Fernet encrypted password and use "Encrypted Password:" label
file.write(f"Included - Lowercase: {args.lower}, Uppercase: {args.upper}, Digits: {args.digits}, Special Characters: {args.specials}\n")
file.write("-" * 40 + "\n")

print("πŸ”’ Password encrypted and saved to 'saved_passwords.txt")


if __name__ == '__main__':
main()
48 changes: 48 additions & 0 deletions Secure_Password_Manager/cli/view_passwords_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import base64

def view_passwords(filename="saved_passwords.txt"):
try:
with open(filename, "r") as file:
lines = file.readlines()

# Temperory variable to store each password block info
timestamp = label = encoded_password = ""
included_options = ""

print("\nπŸ” Saved Passwords:\n")

for line in lines:
line = line.strip()

if line.startswith("["): # Timestamp line
timestamp = line.strip("[]")

elif line.startswith("Label:"):
label = line.split("Label:")[1].strip()

elif line.startswith("Encoded Password:"):
encoded_password = line.split("Encoded Password:")[1].strip()
try:
decoded_password = base64.b64decode(encoded_password.encode()).decode()
except Exception as e:
decoded_password = f"[Error decoding password: {e}]"

elif line.startswith("Included"):
included_options = line.split("Included -")[1].strip()

elif line.startswith("-" * 10): # Block ends here
print(f"πŸ“… Date/Time: {timestamp}")
print(f"🏷️ Label: {label}")
print(f"πŸ”“ Decoded Password: {decoded_password}")
print(f"πŸ”§ Options Included: {included_options}")
print("-" * 40)

except FileNotFoundError:
print("❌ saved_passwords.txt not found.")

except Exception as e:
print(f"❌ An error occured: {e}")

# Run the function
if __name__ == '__main__':
view_passwords()
Loading
Loading