You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

153 lines
5.2 KiB
Python

import base64
import pickle
from math import log2
from password_strength import PasswordStats
from getpass import getpass as gp
from secrets import token_urlsafe
from random import randint as rint, SystemRandom as sr
from atexit import register
from gc import collect
from os import urandom, path, remove
from cryptography.fernet import Fernet, InvalidSignature, InvalidToken
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
def encrypt_db(password):
binpass = password.encode()
salt = urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA512(),
length=32,
salt=salt,
iterations=1500000,
)
key = base64.urlsafe_b64encode(kdf.derive(binpass))
fernet = Fernet(key)
with open("database/db.dat", "rb") as f:
data = f.read()
encr = fernet.encrypt(data)
with open("database/db.asc", "wb") as f:
f.write(encr)
with open("database/db.s", "wb") as f:
f.write(salt)
def decrypt_db(password):
with open("database/db.s", "rb") as f:
salt = f.read()
binpass = password.encode()
kdf = PBKDF2HMAC(
algorithm=hashes.SHA512(),
length=32,
salt=salt,
iterations=1500000,
)
key = base64.urlsafe_b64encode(kdf.derive(binpass))
fernet = Fernet(key)
with open("database/db.asc", "rb") as f:
encrypted_data = f.read()
decr = fernet.decrypt(encrypted_data)
with open("database/db.dat", "wb") as f:
f.write(decr)
with open("database/db.dat", "rb") as f:
while True:
try:
db = pickle.load(f)
except EOFError:
print("\nDatabase loaded.")
break
shred()
def shred():
with open("database/db.dat", "wb") as f:
for _ in range(5):
f.seek(0)
f.write(urandom(path.getsize("database/db.dat")))
remove("database/db.dat")
def clearmem():
db = rint(100000000000000000000000000000000000000000000000000000000000, 999999999999999999999999999999999999999999999999999999999999)
db = None
def gen():
while True:
length = int(input("Enter password length (above 8 only): "))
if length <= 7:
print("The password is too short. Please enter it again.")
else:
break
pool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789`~@#$%^&*()-_=+]}[{\"';:.>,</?"
strength = ''.join(sr().choice(pool) for i in range(length))
print(strength)
def strength():
password = gp(prompt = "\nEnter the password to check its strength (hidden for privacy!): ")
if password in common_passwords:
print("Your password is in the list of 1000 of the most common passwords. Change your password immediately.")
else:
poolsize = 0
for l in password:
if l.islower():
poolsize += 26
elif l.isupper():
poolsize += 26
elif l.isdigit():
poolsize += 10
else:
poolsize += 32
entropy = log2(poolsize**len(password))
passstrength = PasswordStats(strength).strength()
if passstrength < 0.33:
print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is extremely weak. Please change it.\n")
elif passstrength >= 0.33 and passstrength < 0.66:
print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is of fair strength. Please consider changing it to a stronger one.\n")
elif passstrength >= 0.66 and passstrength < 0.80:
print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is strong.\n")
elif passstrength >= 0.80 and passstrength < 0.9:
print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is incredibly strong.\n")
else:
print(f"[PASSWORD STRENGTH]: {passstrength}\n[PASSWORD ENTROPY]: {entropy} bits\nYour password is practically uncrackable.\n")
global db
register(clearmem)
with open("files/strength/common-passwords.txt", "r") as f:
common_passwords = f.read()
print("\nkeyvault initialized.")
for _ in range(4):
try:
if _ != 3:
password = gp(prompt = "\nEnter your password (hidden for privacy!): ")
decrypt_db(password)
break
else:
print(" You have exceeded the maximum number of tries.")
exit()
except (InvalidSignature, InvalidToken):
print("Incorrect password.", end = '')
print("keyvault is ready to use! Type 'help' for a list of commands.\n")
while True:
command = input("> ").lower()
if command == 'help':
print("\nUsage:\n\nls - list entires\nrm - remove entry\ngen - generate a password or username\nstrength - check password strength\nedit - edit an entry\nshow/view - view an entry\nfind/search - open search wizard\nhelp - display this message\nversion - print current version\n")
elif command == 'version':
print("keyvault: v1.0.0")
elif command == 'gen':
gen()
elif command == 'strength':
strength()