提问人:Flash_Steel 提问时间:2/13/2023 更新时间:2/13/2023 访问量:118
在 Python 中将带有字符串键和字节值的字典保存到文件
Saving a dictionary with string keys and bytes values to file in Python
问:
我正在编写一个 python 程序,它应该能够在 Windows、iOS 和 Android 上运行。
为了处理登录,我有一个 目前,我手动将任何字符串转换为二进制,并将它们全部连接成一个二进制字符串,我在从文件加载凭据时解析。一旦它采用可读的二进制格式文件,I/O 就非常微不足道了dict
{key_string: hashed_password_bytes}
代码很长(如下)。有谁知道一个包可以将字典写入文件,而不是使用明文,它可以做同样的工作?
我尝试过的软件包,但找不到合适的使用方法
- 泡菜。由于代码注入风险 https://docs.python.org/3/library/pickle.html 而丢弃
- YAML、JSON 等,因为我不想使用明文解决方案来存储凭据。
- Struct 要求您在打开之前知道变量和字符串变量的长度。
- Netstruct 允许可变长度的字符串,但是你,我不知道如何将字典解压缩到其中,或者所需的格式字符串以返回未知数量的字符串和字节变量的混合。
- Pyvault 可以消除此任务的痛苦,但不幸的是它需要 sqlcipher,我不想在运行该程序的每台设备上安装它。
当前解决方案(在经过大量调试后,打印调用显然将被删除):
import scrypt
import os
MAX_TIME = 0.5 # Set here for ease of changing
FILE_001_DAT_LOCATION = "Source/001.dat"
DATA_LENGTH = 64 # Data length for hashing password
ENCODING_STRING = 'utf-8' # Used in all string encode and decode
PACKING_SIZE_STRING_LENGTH = 4 # The number of bytes used by the size indicator for the proceeding username/password
SIZE_STRING_FORMAT = '{:0>4}' # Used to format the size integer for packing dictionaries
# Turns {string: bytes} into bytes for writing to file
# Format is username1size, username1, password1size, password1, username2size...
def pack_credentials(credentials: dict):
bytes_out = b""
print("pack_credentials() called. Starting loop")
# Loop over every key and add keys
for key in credentials.keys():
# Pack username
print(f"Encoding username: {key}")
encoded_username = key.encode(ENCODING_STRING)
username_size = len(encoded_username)
print(f"Encoded username has size: {username_size}")
username_size_string = SIZE_STRING_FORMAT.format(username_size)
bytes_out += username_size_string.encode(ENCODING_STRING) + encoded_username
# Pack hashed password
print(f"Encoding password: {str(credentials[key])}")
password_size = len(credentials[key])
print(f"Hashed password has size: {password_size}")
password_size_string = SIZE_STRING_FORMAT.format(password_size)
bytes_out += password_size_string.encode(ENCODING_STRING) + credentials[key]
print("Packing complete. Returning bytes.")
return bytes_out
# Hash a raw password and return - for adding new credentials to the dictionary
def hash_password(password):
return scrypt.encrypt(os.urandom(DATA_LENGTH), password, maxtime=MAX_TIME)
# Turns {string: bytes} into bytes for writing to file
# Format is username1size, username1, password1size, password1, username2size...
def unpack_credentials(bytes_in: bytes):
credentials_out = {} # Defined here to add to in loop
slice_start = 0 # Starting index for next slice from bytes_in
slice_end = slice_start + PACKING_SIZE_STRING_LENGTH # Ending index for next slice from bytes_in
bytes_in_length = len(bytes_in)
print("unpack_credentials() called. Starting loop")
# Loop over every key and add keys
while slice_end < bytes_in_length:
# Unpack username
print(f"Unpacking username size")
username_length_bytes = bytes_in[slice_start:slice_end]
print(f"Username size: {username_length_bytes}")
print(f"Unpacking username")
slice_start = slice_end
slice_end = slice_end + int(username_length_bytes.decode(ENCODING_STRING))
username_bytes = bytes_in[slice_start:slice_end]
print(f"Username: {username_bytes.decode(ENCODING_STRING)}")
# Pack hashed password
print(f"Unpacking password size")
slice_start = slice_end
slice_end = slice_end + PACKING_SIZE_STRING_LENGTH
password_length_bytes = bytes_in[slice_start:slice_end]
print(f"Password size: {password_length_bytes.decode(ENCODING_STRING)}")
slice_start = slice_end
slice_end = slice_end + int(password_length_bytes.decode(ENCODING_STRING))
print(f"Unpacking password")
password_bytes = bytes_in[slice_start:slice_end]
#Prepare for next iteration
slice_start = slice_end
slice_end = slice_end + PACKING_SIZE_STRING_LENGTH
#Populate dict
credentials_out[username_bytes.decode(ENCODING_STRING)] = password_bytes
print("Unpacking complete. Returning dict.")
return credentials_out
if __name__ == '__main__':
# appGUI = MyApp()
# appGUI.run()
original_credentials = {"User 1 boiiiiiii": hash_password("password1wEDFRAwerwq rq"),
"Sonic the hedgehog": hash_password("password2qwergasdfghwerterwqgdfsg"),
"Misty water colour memories": hash_password("password3qdaserfgwqeryhger5wtywrthsfdghsd"),
"Niko the big black dog": hash_password("password4eadgrasewrdgerwqttgeqrwtgdfgewrtyertertgeertet")}
credentials_binary = pack_credentials(original_credentials)
new_credentials = unpack_credentials(credentials_binary)
print(
f"Do password hashes match? {original_credentials['User 1 boiiiiiii'] == new_credentials['User 1 boiiiiiii']}")
答: 暂无答案
评论
json
+zip
?