gpt4 book ai didi

python - 在 Python 中使用 Fernet 进行对称加密 - 主密码用例

转载 作者:行者123 更新时间:2023-12-03 17:11:56 25 4
gpt4 key购买 nike

我一直在尝试了解对称加密的工作原理以及如何将其集成到我的 CLI 应用程序中,但我遇到了一些我将在下面描述的问题。

我的用例如下:

  • 我有一个 CLI 应用程序( SQLAlchemy + click + Python 3.8 ),它将是一个非常简单的密码管理器(个人使用)。
  • 开始时,我想向用户询问主密码,以便他能够从数据库中检索任何信息。如果用户还没有主密码,我会请他创建一个。我希望所有数据都使用相同的主 key 进行加密。

  • 要做到以上所有,我认为对称加密是最合适的, Fernet想到了,所以我开始写一些代码:

    import base64

    from cryptography.fernet import Fernet, InvalidToken
    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC


    def generate_key_derivation(salt, master_password):
    kdf = PBKDF2HMAC(
    algorithm=hashes.SHA256(),
    length=32,
    salt=salt,
    iterations=100000,
    backend=default_backend()
    )
    key = base64.urlsafe_b64encode(kdf.derive(master_password.encode()))
    return key


    def encrypt(key, value_to_encrypt):
    f = Fernet(key)
    encrypted_key = f.encrypt(value_to_encrypt.encode())
    return encrypted_key


    def decrypt(key, encrypted_key):
    f = Fernet(key)
    try:
    return f.decrypt(encrypted_key)
    except InvalidToken:
    return b''

    现在,我有点试图从文档中理解:

    In this scheme, the salt has to be stored in a retrievable location in order to derive the same key from the password in the future.



    在我看来,这意味着:将盐存储在数据库中,并在用户每次尝试使用应用程序时使用它。然后,运行用户通过 key 派生函数插入的主密码并检查它是否匹配...... key ? 但是我没有初始 key ,因为我第一次没有将它与盐一起存储。如果我要保存它,难道没有人可以随意使用它来加密和解密数据吗?

    用于防止上述情况的常用解决方案是什么?

    这是一个使用 click 的小型 POC :

    import os
    import click

    from models import MasterPasswordModel


    @click.group(help="Simple CLI Password Manager for personal use")
    @click.pass_context
    def main(ctx):
    # if the user hasn't stored any master password yet,
    # create a new one
    if MasterPasswordModel.is_empty():

    # ask user for a new master password
    master_password = click.prompt(
    'Please enter your new master password: ',
    hide_input=True
    )

    # generate the salt
    salt = os.urandom(16)

    # generate key_derivation
    # this isn't stored because if it does anyone would be able
    # to access any data
    key = generate_key_derivation(salt, master_password)

    # store the salt to the DB
    MasterPasswordModel.create(salt)

    # if the user stored a master password, check if it's valid and
    # allow him to do other actions
    else:
    # ask user for existing master password
    master_password = click.prompt(
    'Please enter your new master password: ',
    hide_input=True
    )

    # get existing master password salt from DB
    salt = MasterPasswordModel.get_salt()

    # generate key_derivation
    key = generate_key_derivation(salt, master_password)

    # At this point I don't know how to check whether the `key` is
    # valid or not since I don't have anything to check it against.

    # what am I missing?

    我希望这一切都是有道理的。作为 TL;DR,我认为问题是:我如何安全地存储 key 以便我可以检索它以进行进一步检查?或者这甚至是应该如何做的事情?我错过了什么?我确定我误解了一些事情:)

    LE:正如其中一条评论中所指出的,看起来我可能有一个解决方案,但我仍然在这个过程中陷入困境。在 this answer它规定:

    If you're not doing this already, I'd also strongly recommend not using the user-supplied key directly, but instead first passing it through a deliberately slow key derivation function such as PBKDF2, bcrypt or scrypt. You should do this first, before even trying to verify the correctness of the key, and immediately discard the original user-supplied key and use the derived key for everything (both verification and actual en/decryption).



    因此,让我们以所有步骤为例:

    1) 我第一次被要求输入主密码。它不存在于数据库中,所以,显然,我必须创建并存储它。

    2) 除了新生成的盐,我必须保存提供的主密码的哈希值(例如,我将使用 SHA-256)。

    3)我现在有一个包含盐和散列主密码的记录,所以我可以继续使用该应用程序。我现在想在 DB 中创建一个新记录,据说将使用我的 key 对其进行加密。

    问题是... 什么键 ?如果我要应用上面写的内容,我必须使用我的 generate_key_derivation()函数使用来自 DB 的 salt 和散列主密码,并将其用于加密/解密。但是,如果我这样做,没有人能够只获取存储在数据库中的 hash_key,并使用相同的 generate_key_derivation为所欲为?

    那么,我错过了什么?

    最佳答案

    我不是加密专家,但我认为这个想法是存储盐和派生 key 的散列,如下所示:

  • 第一次获取主密码
  • 生成盐
  • 使用盐和主密码派生一个新 key
  • 丢弃主密码
  • 散列派生 key
  • 将盐和派生 key 存储在数据库中
  • 使用派生 key 加密存储的密码

  • 稍后使用盐和哈希来验证派生 key 是否真实,如下所示:
  • 获取主密码
  • 从数据库中获取盐和哈希
  • 使用盐和主密码派生 key
  • 丢弃主密码
  • 散列派生 key
  • 通过查看哈希是否与数据库中的哈希匹配来验证派生 key
  • 如果不匹配,退出
  • 否则,使用派生 key 解密其他密码。
  • 关于python - 在 Python 中使用 Fernet 进行对称加密 - 主密码用例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61985537/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com