我目前正在编写自己的小密码管理器
这是你的第一个错误。这种复杂的东西有许多微妙的陷阱,即使是专家有时也会陷入其中,如果在这方面没有足够的经验,你就没有机会做出更接近安全的东西。
将密钥存储在 SHA256 哈希中
哦哦...
这并不一定表明你做错了什么,但我强烈怀疑你是否会做对。我假设您在谈论在这里散列的主密码?主密码应使用PBKDF2、bcrypt 或 Argon2 等KDF转换为密钥,然后此密钥用于加密存储的密码。
如果你想有办法验证密码是否正确,存储密钥的哈希应该没问题,但你不能存储密钥本身......如果你存储密钥,任何可以访问你存储的人都拥有一切他们需要解密所有密码!
如果您不是在谈论散列主密码并且您的意思是实际随机生成的密钥,那么我不知道您要在这里完成什么,但是您不应该使用具有大量迭代的慢速 KDF .
或者,您可以对主密码进行两次哈希处理,一次存储为哈希以稍后验证用户输入的密码是否正确,另一次用作加密密钥。根据如何完成,它的范围可能从设计缺陷到完全泄露密钥。
编辑:在看到完整的代码之后,它似乎是第四个选项:你存储密码的哈希值以便稍后检查输入的密码是否正确,然后你哈希这个哈希值作为密钥,这几乎和刚才一样糟糕存储密钥本身。
我通过执行以下操作创建哈希:
def sha256_rounds(raw, rounds=100001):
obj = hashlib.sha256()
for _ in xrange(rounds):
obj.update(raw)
raw = obj.digest()
return obj.digest()
目前还不清楚raw
这里有什么,但我假设它是密码。您正在做的是使用 SHA256 的未加盐哈希。不要尝试创建自己的 KDF!
创建后,它与以下内容一起存储:
key = base64.urlsafe_b64encode(provided_key)
length = len(key)
with open(key_file, "a+") as key_:
front_salt, back_salt = os.urandom(16), os.urandom(16)
key_.write("{}{}{}:{}".format(front_salt, key, back_salt, length))
那么,您是通过对密码进行哈希处理来创建密钥,然后在前后添加随机盐吗?不仅将 2 种不同的盐连接到前后非标准,而且这里没有完成任何事情,因为它是在 KDF 已经完成之后完成的!你只是为了让它们在那里而添加一些随机值。
为了说明这是多么糟糕(截至提交 609fdb5ce976c7e5aa1832670505da60012b73bc),在不需要任何主密码的情况下转储所有存储的密码所需要的只是:
from encryption.aes_encryption import AESCipher
from lib.settings import store_key, MAIN_DIR, DATABASE_FILE, display_formatted_list_output
from sql.sql import create_connection, select_all_data
conn, cursor = create_connection(DATABASE_FILE)
display_formatted_list_output(select_all_data(cursor, "encrypted_data"), store_key(MAIN_DIR))
虽然尝试创建密码管理器可能是一个很好的学习体验,但请不要 将它用于任何远程重要的事情。正如@Xenos 所建议的那样,您似乎没有足够的经验来创建自己的密码管理器确实会有所帮助,这可能是一个更好的学习机会来看看现有的开源密码管理器。