读取Fernet键导致ValueError:Fernet键必须是32个URL安全的base64编码的字节

时间:2018-12-22 16:20:32

标签: python python-3.x csv cryptography

在此功能中,我试图从文件中读取Fernet密钥,如果文件不包含密钥,则创建一个。

    if ((twitterUrl ? twitterUrl.length : 0) +
        (facebookUrl ? facebookUrl.length : 0) +
        (linkedInUrl ? linkedInUrl.length : 0) > 0) {

我在读取文件时遇到困难。读取文件后,密钥的读取方式为:

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)

但是我收到此错误:

b'nNjpIl9Ax2LRtm-p6ryCRZ8lRsL0DtuY0f9JeAe2wG0='

在这一行:

ValueError: Fernet key must be 32 url-safe base64-encoded bytes.

任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

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

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

>>> key = Fernet.generate_key()
>>> key
b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='

密钥正按原样写入文件中

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

如果我们查看文件,则可以看到内容与预期不符-表示已将python字节串写入文件的b

$  cat keys.csv 
key
b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='

csv.writer对尚未为字符串的任何值调用str。如果在str实例上调用bytes,则会得到字节实例的字符串化的 repr ,而不是bytes实例的解码值想要。

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

因此解决方案是在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
>>>

这为我们提供了所需的文件内容:

$  cat keys.csv 
key
ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg=

其余代码按预期工作:

>>> 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>

一个调试技巧。使用print()调试代码时,打印对象的repr有时会更好,而不是在对象上调用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