Read Fernet Key Causes ValueError: Fernet key must be 32 url-safe base64-encoded bytes

Lyr*_*ell 6 python csv cryptography python-3.x

In this function I am trying to read a Fernet key from a file, or create one if the file doesn't contain a key.

from cryptography.fernet import Fernet
import csv


with open("Keys.txt","rU") as csvfile:
    reader=csv.reader(csvfile)
    KeyFound=0
    print(KeyFound)
    for row in reader:
        try:
            print(row[0])
        except IndexError:
            continue
        if len(row[0])>4:
            print("KEY FOUND")
            KeyFound=1
            print(KeyFound)
            Key=row[0]
            print(Key)
            print(KeyFound)
        else:
            pass
if KeyFound==0:
    Key = Fernet.generate_key()
    print(Key)
    print("Created Key")
    csvfile.close()
#Writing Key to textfile
with open("Keys.txt", "w+") as csvfile:
    headers = ['key']
    writer=csv.DictWriter(csvfile, fieldnames=headers)
    writer.writeheader()
    writer.writerow({'key': Key})
    csvfile.close()
print(Key)
Ecy = Fernet(Key)
Run Code Online (Sandbox Code Playgroud)

I am having difficulty reading the file. When the file is read the key is read in as:

b'nNjpIl9Ax2LRtm-p6ryCRZ8lRsL0DtuY0f9JeAe2wG0='
Run Code Online (Sandbox Code Playgroud)

Yet I receive this error:

ValueError: Fernet key must be 32 url-safe base64-encoded bytes.
Run Code Online (Sandbox Code Playgroud)

In this line:

Ecy = Fernet(Key)
Run Code Online (Sandbox Code Playgroud)

Any help would be appreciated.

sna*_*erb 14

这里的问题是密钥是如何写入文件的。

Fernet.generate_key()返回一个bytes实例:

>>> key = Fernet.generate_key()
>>> key
b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='
Run Code Online (Sandbox Code Playgroud)

密钥正在按原样写入文件:

>>> with open('keys.csv', 'w+') as f:
...     headers = ['key']
...     writer = csv.DictWriter(f, fieldnames=headers)
...     writer.writeheader()
...     writer.writerow({'key': key})
... 
49
>>> 
Run Code Online (Sandbox Code Playgroud)

如果我们查看文件,我们可以看到内容不是我们所期望的 -b这表明 python 字节串已写入文件:

$  cat keys.csv 
key
b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='
Run Code Online (Sandbox Code Playgroud)

csv.writer调用str任何还不是字符串的值。如果str被称为一个bytes实例你得到的字符串化再版的字节情况下,而不是它的解码值bytes情况下,这是你想要的东西*

>>> str(key)
"b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='"  # <- note the extra quotes...
>>> key.decode('utf-8')
'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='
Run Code Online (Sandbox Code Playgroud)

所以解决方案是在 接收它之前调用bytes实例的decode方法csv.writer

>>> with open('keys.csv', 'w+') as f:
...     headers = ['key']
...     writer = csv.DictWriter(f, fieldnames=headers)
...     writer.writeheader()
...     writer.writerow({'key': key.decode('utf-8')})
... 
46
>>>
Run Code Online (Sandbox Code Playgroud)

这为我们提供了我们想要的文件内容:

$  cat keys.csv 
key
ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg=
Run Code Online (Sandbox Code Playgroud)

其余代码按预期工作:

>>> with open('keys.csv') as f:
...     reader = csv.reader(f)
...     next(reader)      # <- skip the header row
...     for row in reader:
...         csv_key = row[0]
...         print(Fernet(csv_key))
... 
['key']                   # <- the headers are printed as a side effect of skipping
<cryptography.fernet.Fernet object at 0x7f3ad62fd4e0>
Run Code Online (Sandbox Code Playgroud)

一个调试技巧。当使用print()调试代码,它有时更好的打印对象的再版,而不是调用结果str的对象(这是在print()做)。如果对象是字符串,则尤其如此。例如:

>>> bad_key = str(key)
>>> print(bad_key)                                
b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='      # <- Looks ok...
>>> print(repr(bad_key))
"b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='"    # <- See the problem
>>> 
>>> good_str = 'foo'
>>> bad_str = 'foo '
>>> print(bad_str)
foo                             # <- looks like good_str
>>> print(repr(bad_str))
'foo '                          # <- see the trailing space 
Run Code Online (Sandbox Code Playgroud)

*如果你调用带有-b标志的python -b myscript.pyPython - -BytesWarning当你第一次尝试调用str一个bytes实例时,Python 会发出一个he 。如果使用该-bb标志,则会引发异常。