BCrypt Login System - Proof of Concept.

Introduction

Following on from some of my previous content about data security, I’ve written a short proof of concept program showing how BCrypt can be used to securely store passwords.

I hope you like it, and feedback is always welcome.

Code

main.py

try:
    from user import User
    import os
    import time
except ImportError:
    print("\nError! Necessary libraries unavailable...\n")


def clear():
    time.sleep(2.5)
    os.system('cls' if os.name == 'nt' else 'clear')


username = input("Username: ")
password = input("Password: ")

# Example Username: testUser
# Example Password: testPass

user = User(username, password)

go = True

while go:
    try:
        menu = int(input("\nEnter 1 to login\nEnter 2 to sign up\nEnter 3 to delete your credentials from the database\nEnter 4 to exit\n: "))

        if menu == 1:

            result = user.Authenticate()

            if result == True:
                print(f"\nSuccess!\nYou are logged in as: {user.Username}")
                clear()
            else:
                print("\nError! please try again...")
                clear()

        elif menu == 2:
            
            result = user.SignUp()

            if result == True:
                print(f"\nSuccess!\n\nYou are logged in as: {user.Username}")
                clear()
            else:
                print("\nError! that username is taken...")
                clear()

        elif menu == 3:

            result = user.RemoveUser()

            if result == True:
                print(f"\nThe credentials associated with the username {username} have been deleted.")
                clear()
                # Terminate program as User object must be recreated.
                go = False
            else:
                print("\nPlease make sure you are logged in before deleting your credentials.\n")
                clear()

        elif menu == 4:
            clear()
            go = False

        else:
            print("\nError! Please try again...")
            clear()
    except:
        print("\nAn unexpected error has occurred! Please try again...")
        clear()

user.py

try:
    import bcrypt
    from replit import db
except ImportError:
    print("\nError! Necessary libraries unavailable...\n")


class User:

    IsAuthenticated = False
    Username = ""
    __Attempts = 0


    def __init__(self, username_input, password_input):

        # Initialise private variables
        self.__username_input = username_input
        self.__password_input = password_input

    
    def SignUp(self):
        '''Takes the username and password used to initialise the object, and stores them securely'''

        username = self.__username_input
        # Encode password to UTF-8 for use by BCrypt
        password_bytes = bytes(self.__password_input, "UTF-8")
        # Hash password using the BCrypt algorithm
        hashed_password = bcrypt.hashpw(password_bytes, bcrypt.gensalt(rounds=14))
        
        username_available = False # True for testing - change to False for

        # Checks if the username is available
        try:
            db[username]
        except KeyError:
            username_available = True

        if username_available:
            # Store password in database
            db[username] = hashed_password.decode()
            self.Username = username
            self.IsAuthenticated = True
            return True
        else:
            return False


    def Authenticate(self):
        
        # Default to False
        authenticated = False
        username = self.__username_input
        # Encode password to UTF-8 for use by BCrypt
        password_bytes = self.__password_input.encode("UTF-8")

        # Checks if the username is recognised
        try:
            stored_password = db[username]
        except KeyError:
            return False
        
        # Will return True if the inputted password matches the stored hash
        authenticated = bcrypt.checkpw(password_bytes, stored_password.encode("UTF-8"))

        if authenticated:
            self.IsAuthenticated = True
            self.Username = username
            return True
        else:
            self.__Attempts += 1
            return False


    def RemoveUser(self):

        username = self.__username_input

        try:
            # Credentials can only be removed if the user has logged in
            if self.IsAuthenticated == True:
                del db[username]
                self.IsAuthenticated = False
                return True
            else:
                return False
        except:
            return False

Note: The code is also available on repl.it, and is designed to run on there.

Test Credentials

Username: testUser
Password: testPass

-George