Access to your passwords anywhere and anytime without saving anything! https://hrypton.ir/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

256 lines
7.4 KiB

import os
import hashlib
import getpass
from sys import argv as sys_argv
try:
from colorama import Fore, Style
lite_mode = False
except ModuleNotFoundError:
print("Warning: We use 'colorama' library to print colored text.\n"
+ "Until it is not installed, all text print with no color.\n"
+ "You can install it using 'pip3 install colorama' command.")
input("Press ENTER to continue")
print("")
lite_mode = True
HASH_LAYERS_COUNT = 50_000 # Increase this make algorithm slower (and safer)
PASSWORD_MIN_SIZE = 12 # If you want to increase PASSWORD_MIN_SIZE use sha-512
hexChars = "0123456789abcdef"
digits = "0123456789"
lowers = "abcdefghijkmnlopqrstuvwxyz"
uppers = "ABCDEFGHIJKMNLPOQRSTUVWXYZ"
specials = "/~!@#$%^&*_-+=`|\\(){}[]:;\"'<>,.?"
allowedChars = digits + lowers + uppers + specials
home_dir = os.path.expanduser("~")
# Generate colored text
def green(text):
if lite_mode == False:
return Fore.GREEN + text + Style.RESET_ALL
return text
def red(text):
if lite_mode == False:
return Fore.RED + text + Style.RESET_ALL
return text
def bright(text):
if lite_mode == False:
return Style.BRIGHT + text + Style.RESET_ALL
return text
# Clear the screen
def clear():
os.system("cls" if os.name == "nt" else "clear")
# Hashing
def sha256(message):
# encode as UTF-8
msgBuffer = message.encode('UTF-8')
# hash the message
hashBuffer = hashlib.sha256(msgBuffer)
# convert bytes to hex string
hashHex = hashBuffer.hexdigest()
return hashHex
# Repeat hashing
def slowIt(input):
i = 0
while i <= HASH_LAYERS_COUNT:
input = sha256(input)
i += 1
return input
# Check for validation of generated password
def validator(password):
hasDigits = False
hasLowers = False
hasUppers = False
hasSpecials = False
# Check for digits
for digit in digits:
if digit in password:
hasDigits = True
break
# Check for lower cases
for lower in lowers:
if lower in password:
hasLowers = True
break
# Check for upper cases
for upper in uppers:
if upper in password:
hasUppers = True
break
# Check for special charecters
for special in specials:
if special in password:
hasSpecials = True
break
if hasDigits and hasLowers and hasUppers and hasSpecials:
return True
else:
return False
# Return a number for each hex charecter
def charsToNum(input1, input2):
if input1 == "0": return hexChars.index(input2)
if input1 == "1": return hexChars.index(input2)
if input1 == "2": return hexChars.index(input2) + 16
if input1 == "3": return hexChars.index(input2) + 16
if input1 == "4": return hexChars.index(input2) + 32
if input1 == "5": return hexChars.index(input2) + 32
if input1 == "6": return hexChars.index(input2) + 48
if input1 == "7": return hexChars.index(input2) + 48
if input1 == "8": return hexChars.index(input2) + 64
if input1 == "9": return hexChars.index(input2) + 64
if input1 == "a": return hexChars.index(input2) + 80
if input1 == "b": return hexChars.index(input2) + 80
if input1 == "c": return hexChars.index(input2) + 96
if input1 == "d": return hexChars.index(input2) + 96
if input1 == "e": return hexChars.index(input2) + 112
if input1 == "f": return hexChars.index(input2) + 112
return "not allowed input1: " + input1
# Switch hex charecters with an allowed charecter
def switch(input1, input2):
number = int(charsToNum(input1, input2))
# num is a number 0 <= x <= 127
# so make it a number 0 <= x <= allowedChars.size()
number = int(number * (len(allowedChars) - 1) / 127)
return allowedChars[number]
# Give hash chars to switch() function one by one, then to validator() function
def standard(input):
result = ""
i = 0
while i <= 63:
result += switch(input[i], input[i+1])
i += 2
# if its not standard try one more hash
# (to make sure output is standard password
# and website validator gonna accept it)
if validator(result[0:PASSWORD_MIN_SIZE+1]) != True:
result = sha256(result)
result = standard(result)
return result
# Decrease generated password length
def limitIt(input):
if input[len(input) - 1] in lowers: bit1 = True
elif input[len(input) - 1] in digits: bit1 = True
else: bit1 = False
if input[len(input) - 2] in lowers: bit2 = True
elif input[len(input) - 2] in digits: bit2 = True
else: bit2 = False
if bit1 and bit2: return input[0:PASSWORD_MIN_SIZE]
elif not bit1 and bit2: return input[0:PASSWORD_MIN_SIZE + 1]
elif bit1 and not bit2: return input[0:PASSWORD_MIN_SIZE + 2]
elif not bit1 and not bit2: return input[0:PASSWORD_MIN_SIZE + 3]
# Get data and return the password
def pash(masterPass, url, username="", howManyTimeChanged="0"):
value = masterPass + url + username
if int(howManyTimeChanged) != 0:
value += howManyTimeChanged
pash = slowIt(value) # Hash the value 50_000 times
pash = standard(pash) # Generate password
pash = limitIt(pash) # Decrease password length
return pash
# pash -> (slowIt <-> sha256) * 50_000
# -> (starndard <-> switch <-> charsToNum) Repeat until password...
# -> validator (If valid) -> limitIt ...become generated
# (else) -> standard
# The main function
def give_password():
masterPass = getpass.getpass("Enter your Master Password: ")
# Check if master password hash has saved before
if os.path.exists(f"{home_dir}/.Hrypton-py.txt"):
with open(f"{home_dir}/.Hrypton-py.txt", "r") as masterPassHash:
if sha256(masterPass) != masterPassHash.read():
print(bright(red("Err: ")) + "That's incorrect!\n")
give_password()
# Request passwrod repeat and then save it hash
else:
masterPassRepeat = getpass.getpass("Enter your Master Password again: ")
if masterPass == masterPassRepeat:
with open(f"{home_dir}/.Hrypton-py.txt", "w") as masterPassHash:
masterPassHash.write(sha256(masterPass))
print("Your master password hash saved in '~/.Hryton-py.txt'")
else:
print(bright(red("Err: ")) + "They are not match!\n")
give_password()
print("")
if len(sys_argv) == 2:
password = pash(masterPass, sys_argv[1])
if len(sys_argv) == 3:
password = pash(masterPass, sys_argv[1], sys_argv[2])
if len(sys_argv) == 4:
password = pash(masterPass, sys_argv[1], sys_argv[2], sys_argv[3])
# Print the password
print(f" {'*' * (len(password) + 4)}")
print(f"Your password is: * {green(password)} *")
print(f" {'*' * (len(password) + 4)}\n")
input("Press ENTER to exit and clear the screen!")
clear()
# Main
if not os.path.exists(f"{home_dir}/.Hrypton-py"):
os.mkdir(f"{home_dir}/.Hrypton-py")
# If there is no problem with args
if (len(sys_argv) >= 2) and (len(sys_argv)<= 4):
give_password()
# If args are more or fewer than it must
else:
print("You must give args like this:")
print("hrypton <URL> <Username> <How_many_time_changed>\n")
print("'Username' and 'How many time changed' are optional.")