【问题标题】:Read Fernet Key Causes ValueError: Fernet key must be 32 url-safe base64-encoded bytesRead Fernet Key Causes ValueError: Fernet key must be 32 url-safe base64-encoded bytes
【发布时间】:2019-05-22 16:00:06
【问题描述】:

在此函数中,我尝试从文件中读取 Fernet 密钥,或者如果文件不包含密钥,则创建一个。

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.

在这一行:

Ecy = Fernet(Key)

任何帮助将不胜感激。

【问题讨论】:

  • 执行f = Fernet(b'nNjpIl9Ax2LRtm-p6ryCRZ8lRsL0DtuY0f9JeAe2wG0=') 对我来说很好。
  • 如果您直接将字节字符串放入命令而不是从文本文件中读取它,我相信它确实可以正常工作。必须与 csv 阅读器有关。
  • 那么,您复制的字节字符串与print(Key) 的输出不完全一致吗?
  • 不,但如果您查看错误,则密钥的格式一定不正确。

标签: python python-3.x csv cryptography


【解决方案1】:

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

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

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

$  cat keys.csv 
key
b'ZmDfcTF7_60GrrY167zsiPd67pEvs0aGOv2oasOM1Pg='

csv.writer 在任何不是字符串的值上调用str。如果在bytes 实例上调用str,您将获得字节实例的字符串化repr,而不是bytes 实例的解码值,这就是您想要的*.

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

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

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

* 如果您使用-b 标志调用Python - python -b myscript.py - 当您第一次尝试在bytes 实例上调用str 时,Python 将发出BytesWarning。如果使用-bb 标志,则会引发异常。

【讨论】:

  • 非常感谢,我现在将 repr() 添加到我的调试库中。
猜你喜欢
  • 2022-12-26
  • 1970-01-01
  • 2020-06-12
  • 1970-01-01
  • 2022-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-03
相关资源
最近更新 更多