Search code examples
pythonencryptioncryptographybcryptencryption-symmetric

why am I getting cryptography fernet InvalidToken when using the same key


Hello so I am making a password manager and I want to encrypt the password file, so I generate and create the first password and when I read it and decrypt it reads it. And then when making another password it creates it but then when decrypting it throws an error. From what I can see I am using the same key. Here is the code:

#imports
import random,string,os,sys
from cryptography.fernet import Fernet
import bcrypt

if os.path.isfile('salt.txt'):
    #Gets the salt
    with open('salt.txt','rb') as saltfile:
        salt = saltfile.read()

else:
    with open('salt.txt','wb')as saltfile:
        salt = bcrypt.gensalt()
        saltfile.write(salt)
        saltfile.close()

#Hashes the item
def hashPass(item):
    global passwordOut
    hashed = bcrypt.hashpw(item,salt)
    passwordOut = hashed
    return passwordOut

#Password Generator
def setPassword(length=30,char=string.ascii_letters+string.digits+string.punctuation):
    global generatedPassword
    generatedPassword= ''.join(random.choice(char) for x in range(length))
    return generatedPassword

if os.path.isfile('mykey.key') == True:
    #Opens the key
    with open('mykey.key', 'rb') as mykey:
        print('True')
        key = mykey.read()
        f = Fernet(key)
        mykey.close()
elif os.path.isfile('mykey.key')== False:
    print('False')
    # Generates a kay
    key = Fernet.generate_key()
    # Writes a new key
    with open('mykey.key', 'wb') as mykey:
        mykey.write(key)
        f = Fernet(key)
        mykey.close()

#Sets the key

#Stating initalization
print("Hello and welcome to your password manager!")

while True:
    #If there is a user file
    if os.path.isfile('user.txt'):
        #Read the user file
        with open('user.txt','rb') as user_file:
            file = user_file.read()

        #Gets the inputs
        getUser = input("Enter your username ").encode('utf-8')
        getPass = input('Enter your password: ').encode('utf-8')

        #Hashes the inputs through the hashing funcion
        hashPass(item=getUser)
        usr = passwordOut
        hashPass(item=getPass)
        passw = passwordOut

        #If the users hashed input is the same in the users file it carries on with the procedure
        if usr in file and passw in file:
            while True:
                print("""Pick from the list of what you want to do:
                1. Generate a new password
                2. See passwords
                3. Quit""")

                usrinput = int(input('Enter a number from the menu: '))

                if usrinput == 1:
                    print("\nGenerating password...")
                    setPassword()
                    usrinput = input("What is the password for: ")
                    splitter = ': '
                    #
                    if os.path.isfile('passwordenc.txt'):
                        with open('passwordenc.txt','ab')as password_file:
                            var = usrinput + splitter + generatedPassword + '\n'
                            encrypted = f.encrypt(bytes(var.encode('utf-8')))
                            password_file.write(encrypted)
                            print("Your new password for: "+usrinput)
                            print("And the password is: "+generatedPassword)
                            password_file.close()
                    else:
                        with open('passwordenc.txt','wb')as password_file:
                            var = usrinput + splitter + generatedPassword + '\n'
                            encrypted = f.encrypt(bytes(var.encode('utf-8')))
                            password_file.write(encrypted)
                            print("Your new password for: " + usrinput)
                            print("And the password is: " + generatedPassword)
                            password_file.close()

                if usrinput == 2:
                    if os.path.isfile('passwordenc.txt'):
                        with open('passwordenc.txt','rb') as password_file:
                            read = password_file.read()
                            decrypt = f.decrypt(read)
                            print(decrypt)
                            password_file.close()

                    else:
                        print('File not found! Need to create a new file.')

                if usrinput == 3:
                    quit()


        #If not the same it loops back around
        else:
            print("\nUser not found!\n")


    #If there is no file:
    else:
        #Gets a user input
        username = input('Enter a username: ').encode('utf-8')
        password = input('Enter a password, cannot be changed! ').encode('utf-8')

        #Hashes the user input
        hashPass(item=username)
        usr = passwordOut
        hashPass(item=password)
        passw = passwordOut

        #Writes the user input
        with open('user.txt','wb') as user:
            user.write(usr)
            user.write(passw)
        print('\nUser has been created!\n')

Here is the terminal code:

C:\Users\James\Documents\passwords\venv\Scripts\python.exe C:/Users/James/Documents/passwords/main.py
True
Hello and welcome to your password manager!
Enter your username james
Enter your password: Kaits_1204
Pick from the list of what you want to do:
                1. Generate a new password
                2. See passwords
                3. Quit
Enter a number from the menu: 2
Traceback (most recent call last):
  File "C:\Users\James\Documents\passwords\venv\lib\site-packages\cryptography\fernet.py", line 119, in _verify_signature
    h.verify(data[-32:])
  File "C:\Users\James\Documents\passwords\venv\lib\site-packages\cryptography\hazmat\primitives\hmac.py", line 74, in verify
    ctx.verify(signature)
  File "C:\Users\James\Documents\passwords\venv\lib\site-packages\cryptography\hazmat\backends\openssl\hmac.py", line 75, in verify
    raise InvalidSignature("Signature did not match digest.")
cryptography.exceptions.InvalidSignature: Signature did not match digest.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/James/Documents/passwords/main.py", line 106, in <module>
    decrypt = f.decrypt(read)
  File "C:\Users\James\Documents\passwords\venv\lib\site-packages\cryptography\fernet.py", line 80, in decrypt
    return self._decrypt_data(data, timestamp, time_info)
  File "C:\Users\James\Documents\passwords\venv\lib\site-packages\cryptography\fernet.py", line 137, in _decrypt_data
    self._verify_signature(data)
  File "C:\Users\James\Documents\passwords\venv\lib\site-packages\cryptography\fernet.py", line 121, in _verify_signature
    raise InvalidToken
cryptography.fernet.InvalidToken

Process finished with exit code 1


Solution

  • The problem is that you take input of user for chosen account password then you append splitter and random generated password then '/n'. After that you encrypt this var using fernet. This method will work to view your first password since with first password you read and decrypt whole file but not with multiple encrypted passwords since each var encryption is unique (having different IV) which means that to decrypt all the passwords you will need a way to signal the end of an encrypted password and beginning of another encrypted password so that you pass to ferent the correct ciphertext with correct margins. This can be done by simply adding --END OF PASSWORD-- after each encryption write to password file. Then during reading of passwords you can just split pass file on these margins and pass result to fernet.

    NOTE: dont use this code as your password manager since although you encrypt your passwords you are leaving your master password in mykey.key unencrypted which makes this totally useless.

    import random,string,os,sys
    from cryptography.fernet import Fernet
    import bcrypt
    
    if os.path.isfile('salt.txt'):
        #Gets the salt
        with open('salt.txt','rb') as saltfile:
            salt = saltfile.read()
    
    else:
        with open('salt.txt','wb')as saltfile:
            salt = bcrypt.gensalt()
            saltfile.write(salt)
            #saltfile.close()       # You dont need to close
    
    #Hashes the item
    def hashPass(item):
        global passwordOut
        hashed = bcrypt.hashpw(item,salt)
        passwordOut = hashed
    #    return passwordOut
    
    # Random Password Generator 
    def setPassword(length=30,char=string.ascii_letters+string.digits+string.punctuation):
        global generatedPassword
        generatedPassword= ''.join(random.choice(char) for x in range(length))
        return generatedPassword
    
    if os.path.isfile('mykey.key') == True:
        #Opens the key
        with open('mykey.key', 'rb') as mykey:
            print('True')
            key = mykey.read()
            f = Fernet(key)
    
    elif os.path.isfile('mykey.key')== False:
        print('False')
        # Generates a kay
        key = Fernet.generate_key()
        # Writes a new key
        with open('mykey.key', 'wb') as mykey:
            mykey.write(key)
            f = Fernet(key)
            #mykey.close()          # with doesnt need file to be closed
    
    #Sets the key
    
    #Stating initalization
    print("Hello and welcome to your password manager!")
    
    while True:
        #If there is a user file
        if os.path.isfile('user.txt'):
            #Read the user file
            with open('user.txt','rb') as user_file:
                file = user_file.read()
                print("File ", file)
    
            #Gets the inputs
            getUser = input("Enter your username ").encode('utf-8')
            getPass = input('Enter your password: ').encode('utf-8')
    
            #Hashes the inputs through the hashing funcion
            hashPass(item=getUser)
            usr = passwordOut
            hashPass(item=getPass)
            passw = passwordOut
    
            #If the users hashed input is the same in the users file it carries on with the procedure
            if usr in file and passw in file:
                while True:
                    print("""Pick from the list of what you want to do:
                    1. Generate a new password
                    2. See passwords
                    3. Quit""")
    
                    usrinput = int(input('Enter a number from the menu: '))
    
                    if usrinput == 1:
                        print("\nGenerating password...")
                        setPassword()
                        usrinput = input("What is the password for: ")
                        splitter = ': '
                        #
                        if os.path.isfile('passwordenc.txt'):
                            with open('passwordenc.txt','ab')as password_file:
                                var = usrinput + splitter + generatedPassword + '\n'
                                encrypted = f.encrypt(bytes(var.encode('utf-8')))
                                password_file.write(encrypted)
                                password_file.write(b"--END OF PASSWORD--")
    
                                print("Your new password for: "+usrinput)
                                print("And the password is: "+generatedPassword)
                                
    
                        else:
                            with open('passwordenc.txt','wb')as password_file:
                                var = usrinput + splitter + generatedPassword + '\n'
                                encrypted = f.encrypt(bytes(var.encode('utf-8')))                    
                                password_file.write(encrypted)
                                password_file.write(b"--END OF PASSWORD--")
    
                                print("Your new password for: " + usrinput)
                                print("And the password is: " + generatedPassword)
    
    
                    if usrinput == 2:
                        if os.path.isfile('passwordenc.txt'):                    
                            with open('passwordenc.txt','r') as password_file:
                                whole_file = password_file.read()
                                password_list = whole_file.split("--END OF PASSWORD--")                        
                                for password in password_list:
                                    if password:
                                        decrypt = f.decrypt(bytes(password, encoding="utf-8"))
                                        print("Decrypted pass: ", decrypt)                
    
                        else:
                            print('File not found! Need to create a new file.')
    
                    if usrinput == 3:
                        quit()
    
    
            #If not the same it loops back around
            else:
                print("\nUser not found!\n")
    
    
        #If there is no file:
        else:
            #Gets a user input
            username = input('Enter a username: ').encode('utf-8')
            password = input('Enter a password, cannot be changed! ').encode('utf-8')
    
            #Hashes the user input
            hashPass(item=username)
            usr = passwordOut
            hashPass(item=password)
            passw = passwordOut
    
            #Writes the user input
            with open('user.txt','wb') as user:
                user.write(usr)
                user.write(passw)
            print('\nUser has been created!\n')