user11880533
user11880533

Reputation:

Using supplied key to encrypt text python

How do I encrypt with my own key?

I've searched over the net to do this. How do I encrypt with my own key? In python I prefer cryptography though. It keeps popping out the error Fernet key must be 32 url-safe base64-encoded bytes and TypeError: a bytes-like object is required, not 'str'. I am trying to create a private variable function. I'm python new-comer.

Here is my uncompleted code. Thank you for your help.

from cryptography.fernet import Fernet
import inspect
import hashlib
import base64     #Fernet key must be 32 url-safe base64-encoded bytes

def encode(key, string):
    encoded_chars = []
    for i in xrange(len(string)):
        key_c = key[i % len(key)]
        encoded_c = chr(ord(string[i]) + ord(key_c) % 256)
        encoded_chars.append(encoded_c)
    encoded_string = "".join(encoded_chars)
    return base64.urlsafe_b64encode(encoded_string)

class private:
    class sec_storage:
        data = dict()
        hashed_data = dict()
    class var:
        def create(var,value):
            # creates key based on caller
            key = hashlib.sha224(str(inspect.stack()).encode()).hexdigest()
            cipher_suite = Fernet(base64.b64encode(key))   #Fernet key must be 32 url-safe base64-encoded bytes
            # encrypts using key
            encoded_text = cipher_suite.encrypt(value)
            # prepares storage
            hashed_var = hashlib.sha224("plus".join(list(var.encode(),key[:12])).hexdigest())
            hashed_value = hashlib.sha224(value.encode()).hexdigest()[12:30]
            private.sec_storage.data[hashed_var] = encoded_text
            private.sec_storage.hashed_data[hashed_var] = hashed_value

        def read(var):
            # creates key based on caller
            key = hashlib.sha224(str(inspect.stack()).encode()).hexdigest()
            cipher_suite = Fernet(base64.b64encode(key))     #Fernet key must be 32 url-safe base64-encoded bytes
            # retrieve var
            hashed_varname = hashlib.sha224("plus".join(list(var.encode(),key[:12])).hexdigest())
            try:
                hashed_var = private.sec_storage.data[hashed_varname]
            except NameError:
                raise NameError("Requested variable not found")
            # decrypts using key
            decoded_text = cipher_suite.decrypt(hashed_var)
            hashed_value = hashlib.sha224(decoded_text.encode()).hexdigest()[12:30]
            # checks if password is correct
            if private.sec_storage.hashed_data[hashed_varname] != hashed_value:
                raise ValueError("Value not as requested")
            return decoded_text
private.var.create("myvar","Hello World!")
print(private.var.read("myvar"))
print(sec_storage.data)

As you can see cipher_suite = Fernet(base64.b64encode(key)) #Fernet key must be 32 url-safe base64-encoded

How do I fix it?

Upvotes: 0

Views: 2038

Answers (1)

Paul Kehrer
Paul Kehrer

Reputation: 14089

The primary issue here is that Fernet expects a url-safe base64 encoded string that decodes to 32 bytes. The security of this construction relies on those 32 bytes containing sufficient entropy such that an attacker can't feasibly guess it.

In your example you're using the SHA224 hash of a stack trace. There are a few issues at play:

  • 224 bits/8 bits per byte=28 bytes, which is not a sufficiently long output.
  • Hashing a stack trace is not a safe method of deriving a key.
  • You've encoded via vanilla base64 when it should use urlsafe_b64encode.

In general it's best to generate your Fernet key with Fernet.generate_key(), but that requires you to store the key somewhere for later use. If you want to generate a key from something like a password the documentation has an example (https://cryptography.io/en/latest/fernet/#using-passwords-with-fernet).

Upvotes: 2

Related Questions