-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSimpleVault.py
More file actions
154 lines (135 loc) · 4.89 KB
/
SimpleVault.py
File metadata and controls
154 lines (135 loc) · 4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import os
import json
import getpass
import hashlib
VAULT_FILE = "vault.bin"
MASTER_PASS_COUNT = 5
SALT_SIZE = 16
def hash_password(pw, salt=None):
if not salt:
salt = os.urandom(SALT_SIZE)
hashed = hashlib.sha256(salt + pw.encode()).digest()
return salt.hex() + ":" + hashed.hex()
def check_password(pw, stored):
salt_hex, hashed_hex = stored.split(":")
salt = bytes.fromhex(salt_hex)
hashed = hashlib.sha256(salt + pw.encode()).digest().hex()
return hashed == hashed_hex
def generate_key(master_passwords):
combined = "".join(master_passwords).encode()
return hashlib.sha256(combined).digest()
def xor_encrypt(data: bytes, key: bytes) -> bytes:
return bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
def encrypt(data: bytes, key: bytes) -> bytes:
return xor_encrypt(data, key)
def decrypt(enc_data: bytes, key: bytes) -> bytes:
return xor_encrypt(enc_data, key)
def create_vault(master_passwords):
key = generate_key(master_passwords)
master_hashes = [hash_password(pw) for pw in master_passwords]
empty_data = json.dumps({"master_hashes": master_hashes, "vault": {}}).encode()
encrypted = encrypt(empty_data, key)
with open(VAULT_FILE, "wb") as f:
f.write(encrypted)
print("Vault created and encrypted.")
def load_vault(master_passwords):
if not os.path.exists(VAULT_FILE):
print("Vault file not found. Creating new vault.")
create_vault(master_passwords)
key = generate_key(master_passwords)
with open(VAULT_FILE, "rb") as f:
enc = f.read()
try:
dec = decrypt(enc, key)
data = json.loads(dec.decode())
for i, h in enumerate(data["master_hashes"]):
if not check_password(master_passwords[i], h):
raise ValueError("Master password incorrect.")
return data, key
except Exception as e:
print("Failed to unlock vault:", e)
return None, None
def save_vault(data, key):
raw = json.dumps(data).encode()
encrypted = encrypt(raw, key)
with open(VAULT_FILE, "wb") as f:
f.write(encrypted)
def input_master_passwords():
print(f"Enter your {MASTER_PASS_COUNT} master passwords:")
return [getpass.getpass(f"Master password {i+1}: ") for i in range(MASTER_PASS_COUNT)]
def add_entry(data):
user = input("New username: ").strip()
if user in data["vault"]:
print("Username exists.")
return
pw = getpass.getpass("Password for this username: ")
data["vault"][user] = pw
print("Entry added.")
def edit_entry(data):
user = input("Username to edit: ").strip()
if user not in data["vault"]:
print("Not found.")
return
pw = getpass.getpass("New password: ")
data["vault"][user] = pw
print("Entry updated.")
def change_master_passwords(data):
print("Changing master passwords. Enter old passwords first.")
old_pwds = input_master_passwords()
for i, h in enumerate(data["master_hashes"]):
if not check_password(old_pwds[i], h):
print("Old master password incorrect. Abort.")
return False
print("Enter new master passwords:")
new_pwds = input_master_passwords()
data["master_hashes"] = [hash_password(pw) for pw in new_pwds]
print("Master passwords updated.")
return new_pwds
def main():
if not os.path.exists(VAULT_FILE):
print("No vault found. Setup your 5 master passwords.")
master_passwords = input_master_passwords()
create_vault(master_passwords)
else:
master_passwords = input_master_passwords()
data, key = load_vault(master_passwords)
if data is None:
print("Cannot unlock vault. Exiting.")
return
while True:
print("\nOptions:")
print("1 - Add new username/password")
print("2 - Edit existing password")
print("3 - Change master passwords")
print("4 - List usernames")
print("5 - View password for username")
print("6 - Exit")
choice = input("Choice: ").strip()
if choice == "1":
add_entry(data)
elif choice == "2":
edit_entry(data)
elif choice == "3":
new_pwds = change_master_passwords(data)
if new_pwds:
master_passwords = new_pwds
key = generate_key(master_passwords)
elif choice == "4":
print("Usernames:")
for u in data["vault"]:
print(" -", u)
elif choice == "5":
u = input("Username to view password: ").strip()
if u in data["vault"]:
print(f"Password for {u}: {data['vault'][u]}")
else:
print("Not found.")
elif choice == "6":
save_vault(data, key)
print("Vault saved. Exiting.")
break
else:
print("Invalid choice.")
save_vault(data, key)
if __name__ == "__main__":
main()