Search code examples
pythonpython-2.7encryptioncryptographypython-cryptography

Is it possible to save a fernet key for a later session?


I am very new at python, I was working on a program that encrypts a text string, then saves it to a file. My program works perfectly when I encrypt then decrypt it in the same session. What I would like to do is: encrypt a file, then close the program, come back to it later and decrypt it. I don't know how the cryptography module works, but judging how it is called the "key" I assume it would be important for security, but I do not know. When I try to save the fernet key to a text file it displays an error message. When I try to decrypt a message that was encrypted in a previous session it displays 4 errors referencing the cryptography module. To conclude, I was wondering if it is possible to use the cryptography module to decrypt data between sessions. If not, is there an alternate way I could complete this task? Thanks for any help. here is my code:

from cryptography.fernet import Fernet
key = Fernet.generate_key()
f = Fernet(key)
sel = input("Would you like to encrypt or decrypt? (1 = encrypt, 2 = decrypt) ")
if sel == 1:
    inp = raw_input("Enter Text: ")  # Type here
    encoded = f.encrypt(inp)
    a, b = encoded[:len(encoded)/2], encoded[len(encoded)/2:]
    print ("YOUR PASSWORD: ")
    print b
    file = open('password.txt', 'w')
    file.write(a)
elif sel == 2:
    inp = raw_input("Enter Password: ")
    file = open('password.txt', 'r')
    a = file.readline()
    combine = (a + inp)
    out = f.decrypt(combine)
    print out

here is the error that occurs when you enter a "password" from a previous session:

Traceback (most recent call last):
  File "/Users/Zak/PycharmProjects/Password/test.py", line 18, in <module>
    out = f.decrypt(combine)
  File "/Users/Zak/PycharmProjects/Password/venv/lib/python2.7/site-packages/cryptography/fernet.py", line 75, in decrypt
    return self._decrypt_data(data, timestamp, ttl)
  File "/Users/Zak/PycharmProjects/Password/venv/lib/python2.7/site-packages/cryptography/fernet.py", line 119, in _decrypt_data
    self._verify_signature(data)
  File "/Users/Zak/PycharmProjects/Password/venv/lib/python2.7/site-packages/cryptography/fernet.py", line 108, in _verify_signature
    raise InvalidToken
cryptography.fernet.InvalidToken

Also this is what happens when you edit the code to save the key to a blank .txt file. Keep in mind this error does not reflect the code above.

Traceback (most recent call last):
  File "/Users/Zak/PycharmProjects/Password/test.py", line 5, in <module>
    file.write(f)
TypeError: expected a character buffer object

Solution

  • With a few modifications, your script can be made to work the way you intended (but read the answer until the end to learn why this might no be an entirely good idea):

    from cryptography.fernet import Fernet
    sel = input("Would you like to encrypt or decrypt? (1 = encrypt, 2 = decrypt) ")
    if sel == 1:
        key = Fernet.generate_key()
        print ("YOUR KEY: ")
        print key
        f = Fernet(key)
        inp = raw_input("Enter Text: ")  # Type here
        encoded = f.encrypt(inp)
        with open('encoded.txt', 'w') as file:
            file.write(encoded)
    elif sel == 2:
        inp = raw_input("Enter Key: ")
        f = Fernet(inp)
        with open('encoded.txt', 'r') as file:
            encoded = file.readline()
        out = f.decrypt(encoded)
        print out
    

    Testing it:

    $ python2 test.py 
    Would you like to encrypt or decrypt? (1 = encrypt, 2 = decrypt) 1
    YOUR KEY: 
    gRNCcDPDnSzqT2RT4nFJA6MYtsJkBG85sMEy9TogRYg=
    Enter Text: This is a secret
    $ python2 test.py 
    Would you like to encrypt or decrypt? (1 = encrypt, 2 = decrypt) 2
    Enter Key: gRNCcDPDnSzqT2RT4nFJA6MYtsJkBG85sMEy9TogRYg=
    This is a secret
    

    You may have noticed that I changed the word PASSWORD into KEY -- because that long string of characters is actually the key (in a URL-safe, base64-encoded form) used for the encrypt() and decrypt() transformations.

    In practice, this is normally not what you would be doing. The key can not be memorized and people would typically store it somewhere in a file and use copy-paste to enter it. This increases the risk that the key will leak.

    As an alternative, a so-called key-derivation mechanism can be used. In that case, the key bytes are not generated randomly with the Fernet.generate_key() function, but they are calculated using a key-derivation function that is applied to a, easier to memorize but well-chosen, passphrase. For an example of that, see the section Using passwords with Fernet.