4

I'm writing a simple password program in Python (new to Python, even newer to encryption), where user accounts and passwords gets saved in a dictionary to a file. I'm encrypting the passwords with the Fernet module. Adding users works fine, but when I'm trying to decrypt the passwords, I get the cryptography.fernet.InvalidToken error, so the problem should be with the key, although I can't see what I'm doing wrong here.

Code snippet:

def generate_master_key():
    my_key_file = "/path/to/passwordfile"
    if os.path.exists(my_key_file):
        with open(my_key_file, 'rb') as myfile:
            master_key = myfile.read()
    else:
        master_key = Fernet.generate_key()
        with open(my_key_file, 'wb') as myfile:
            myfile.write(master_key)
    return master_key
    del master_key


PASSWORDS = json.load(open('accounts'))
key = generate_master_key()
cipher_suite = Fernet(key)

def encrypt(s):
    return cipher_suite.encrypt(base64.encodestring(bytes(s, encoding="ascii")))


def decrypt(token):
    return cipher_suite.decrypt(base64.encodestring(bytes(token, encoding="ascii")))


def add_user():
    print('What is the name of the account you would like to add?')
    account = input()
    print('What is the password of {}?'.format(account))
    pw = getpass.getpass()
    PASSWORDS[account] = encrypt(pw).decode('ascii')
    json.dump(PASSWORDS, open('accounts', 'w'))


def get_password():
    account = sys.argv[1]
    if account in PASSWORDS:
        pyperclip.copy(decrypt(PASSWORDS[account]))
        print('Password for {} copied to clipboard'.format(account))
    else:
        print('There is no account named {}'.format(account))
r4tchet
  • 157
  • 1
  • 2
  • 8
  • 2
    Why do you encode the message bytes and ciphertext bytes before encrypting / decrypting? Fernet works on bytes, not on strings, right? – Maarten Bodewes Apr 10 '18 at 13:26
  • 2
    @MaartenBodewes First I tried simply converting the password to bytes before encrypting (like in the example here https://cryptography.io/en/latest/fernet/), but that gave me issues with json. So I tried a lot of different things, and now I'm just confused – r4tchet Apr 10 '18 at 14:18
  • 2
    The right way is: character-encode (UTF-8), encrypt, encode (base 64) and decode, decrypt, character-decode. That is *if* you require text instead of binary for your ciphertext, otherwise leave out the base 64 encoding/decoding. – Maarten Bodewes Apr 10 '18 at 14:37

1 Answers1

0

If my understanding is right, you are passing to the decrypt method the encoded value of the crypted text, which is not a valid token to decrypt.

Since you pass a encoded value to the crypt, the decrypt should be something like this:

def decrypt(token):
    return base64.decode(cipher_suite.decrypt(token, encoding="ascii"))
Gianluca
  • 3,227
  • 2
  • 34
  • 35