Skip to content

Commit d330440

Browse files
committed
add password manager tutorial
1 parent a488917 commit d330440

File tree

4 files changed

+208
-0
lines changed

4 files changed

+208
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ This is a repository of all the tutorials of [The Python Code](https://www.thepy
4343
- [How to Crack Hashes in Python](https://thepythoncode.com/article/crack-hashes-in-python). ([code](ethical-hacking/hash-cracker))
4444
- [How to Make a Phone Number Tracker in Python](https://thepythoncode.com/article/phone-number-tracker-in-python). ([code](ethical-hacking/phone-number-tracker))
4545
- [How to Make a Login Password Guesser in Python](https://thepythoncode.com/article/make-a-login-password-guesser-in-python). ([code](ethical-hacking/login-password-guesser))
46+
- [How to Build a Password Manager in Python](https://thepythoncode.com/article/build-a-password-manager-in-python). ([code](ethical-hacking/password-manager))
4647

4748
- ### [Machine Learning](https://www.thepythoncode.com/topic/machine-learning)
4849
- ### [Natural Language Processing](https://www.thepythoncode.com/topic/nlp)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# [How to Build a Password Manager in Python](https://thepythoncode.com/article/build-a-password-manager-in-python)
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
import json, hashlib, getpass, os, pyperclip, sys
2+
from cryptography.fernet import Fernet
3+
4+
5+
# Function for Hashing the Master Password.
6+
def hash_password(password):
7+
sha256 = hashlib.sha256()
8+
sha256.update(password.encode())
9+
return sha256.hexdigest()
10+
11+
12+
# Generate a secret key. This should be done only once as you'll see.
13+
def generate_key():
14+
return Fernet.generate_key()
15+
16+
17+
# Initialize Fernet cipher with the provided key.
18+
def initialize_cipher(key):
19+
return Fernet(key)
20+
21+
22+
# Function to encrypt a password.
23+
def encrypt_password(cipher, password):
24+
return cipher.encrypt(password.encode()).decode()
25+
26+
27+
# Function to decrypt a password.
28+
def decrypt_password(cipher, encrypted_password):
29+
return cipher.decrypt(encrypted_password.encode()).decode()
30+
31+
32+
# Function to register you.
33+
def register(username, master_password):
34+
# Encrypt the master password before storing it
35+
hashed_master_password = hash_password(master_password)
36+
user_data = {'username': username, 'master_password': hashed_master_password}
37+
file_name = 'user_data.json'
38+
39+
if os.path.exists(file_name) and os.path.getsize(file_name) == 0:
40+
with open(file_name, 'w') as file:
41+
json.dump(user_data, file)
42+
print("\n[+] Registration complete!!\n")
43+
else:
44+
with open(file_name, 'x') as file:
45+
json.dump(user_data, file)
46+
print("\n[+] Registration complete!!\n")
47+
48+
49+
# Function to log you in.
50+
def login(username, entered_password):
51+
try:
52+
with open('user_data.json', 'r') as file:
53+
user_data = json.load(file)
54+
55+
stored_password_hash = user_data.get('master_password')
56+
entered_password_hash = hash_password(entered_password)
57+
58+
if entered_password_hash == stored_password_hash and username == user_data.get('username'):
59+
print("\n[+] Login Successful..\n")
60+
else:
61+
print("\n[-] Invalid Login credentials. Please use the credentials you used to register.\n")
62+
sys.exit()
63+
64+
except Exception:
65+
print("\n[-] You have not registered. Please do that.\n")
66+
sys.exit()
67+
68+
69+
# Function to view saved websites.
70+
def view_websites():
71+
try:
72+
with open('passwords.json', 'r') as data:
73+
view = json.load(data)
74+
print("\nWebsites you saved...\n")
75+
for x in view:
76+
print(x['website'])
77+
print('\n')
78+
except FileNotFoundError:
79+
print("\n[-] You have not saved any passwords!\n")
80+
81+
82+
# Load or generate the encryption key.
83+
key_filename = 'encryption_key.key'
84+
if os.path.exists(key_filename):
85+
with open(key_filename, 'rb') as key_file:
86+
key = key_file.read()
87+
else:
88+
key = generate_key()
89+
with open(key_filename, 'wb') as key_file:
90+
key_file.write(key)
91+
92+
cipher = initialize_cipher(key)
93+
94+
95+
# Function to add (save password).
96+
def add_password(website, password):
97+
# Check if passwords.json exists
98+
if not os.path.exists('passwords.json'):
99+
# If passwords.json doesn't exist, initialize it with an empty list
100+
data = []
101+
else:
102+
# Load existing data from passwords.json
103+
try:
104+
with open('passwords.json', 'r') as file:
105+
data = json.load(file)
106+
except json.JSONDecodeError:
107+
# Handle the case where passwords.json is empty or invalid JSON.
108+
data = []
109+
110+
# Encrypt the password
111+
encrypted_password = encrypt_password(cipher, password)
112+
113+
# Create a dictionary to store the website and password
114+
password_entry = {'website': website, 'password': encrypted_password}
115+
data.append(password_entry)
116+
117+
# Save the updated list back to passwords.json
118+
with open('passwords.json', 'w') as file:
119+
json.dump(data, file, indent=4)
120+
121+
122+
# Function to retrieve a saved password.
123+
def get_password(website):
124+
# Check if passwords.json exists
125+
if not os.path.exists('passwords.json'):
126+
return None
127+
128+
# Load existing data from passwords.json
129+
try:
130+
with open('passwords.json', 'r') as file:
131+
data = json.load(file)
132+
except json.JSONDecodeError:
133+
data = []
134+
# Loop through all the websites and check if the requested website exists.
135+
for entry in data:
136+
if entry['website'] == website:
137+
# Decrypt and return the password
138+
decrypted_password = decrypt_password(cipher, entry['password'])
139+
return decrypted_password
140+
141+
return None
142+
143+
144+
# Infinite loop to keep the program running until the user chooses to quit.
145+
while True:
146+
print("1. Register")
147+
print("2. Login")
148+
print("3. Quit")
149+
choice = input("Enter your choice: ")
150+
151+
if choice == '1': # If a user wants to register
152+
file = 'user_data.json'
153+
if os.path.exists(file) and os.path.getsize(file) != 0:
154+
print("\n[-] Master user already exists!!")
155+
sys.exit()
156+
else:
157+
username = input("Enter your username: ")
158+
master_password = getpass.getpass("Enter your master password: ")
159+
register(username, master_password)
160+
161+
elif choice == '2': # If a User wants to log in
162+
file = 'user_data.json'
163+
if os.path.exists(file):
164+
username = input("Enter your username: ")
165+
master_password = getpass.getpass("Enter your master password: ")
166+
login(username, master_password)
167+
else:
168+
print("\n[-] You have not registered. Please do that.\n")
169+
sys.exit()
170+
# Various options after a successful Login.
171+
while True:
172+
print("1. Add Password")
173+
print("2. Get Password")
174+
print("3. View Saved websites")
175+
print("4. Quit")
176+
177+
password_choice = input("Enter your choice: ")
178+
if password_choice == '1': # If a user wants to add a password
179+
website = input("Enter website: ")
180+
password = getpass.getpass("Enter password: ")
181+
182+
# Encrypt and add the password
183+
add_password(website, password)
184+
print("\n[+] Password added!\n")
185+
186+
elif password_choice == '2': # If a User wants to retrieve a password
187+
website = input("Enter website: ")
188+
decrypted_password = get_password(website)
189+
if website and decrypted_password:
190+
# Copy password to clipboard for convenience
191+
pyperclip.copy(decrypted_password)
192+
print(f"\n[+] Password for {website}: {decrypted_password}\n[+] Password copied to clipboard.\n")
193+
else:
194+
print("\n[-] Password not found! Did you save the password?"
195+
"\n[-] Use option 3 to see the websites you saved.\n")
196+
197+
elif password_choice == '3': # If a user wants to view saved websites
198+
view_websites()
199+
200+
elif password_choice == '4': # If a user wants to quit the password manager
201+
break
202+
203+
elif choice == '3': # If a user wants to quit the program
204+
break
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
cryptography
2+
pyperclip

0 commit comments

Comments
 (0)