【问题标题】:Proper data encryption with a user-set password in python3在 python3 中使用用户设置的密码进行适当的数据加密
【发布时间】:2023-01-08 09:08:38
【问题描述】:

我一直在寻找合适的数据加密库 在python里用了好久,今天又要用了,不行 找到任何东西,所以有什么方法可以使用 用户设置的密码,如果我发现它通常是不安全的, 如果我找到一个好的解决方案,它不支持用户设置密码, 意思是我卡住了,有什么办法吗?

这是一些伪代码:

import encryption

encryptor: encryption.Crypt = encryption.Crypt("my secret password")

encryptor.encrypt("hello this is my very secret string")  # => 9oe gyu yp9q*(Y 28j
encryptor.decrypt("9oe gyu yp9q*(Y 28j")  # => hello this is my very secret string

我不在乎它是不是一个物体,因为我只在乎 它也可以是一个接受密码的函数:

import encryption

encryption.encrypt("hello this is my very secret string", "my secret password")  # => 9oe gyu yp9q*(Y 28j
encryption.decrypt("9oe gyu yp9q*(Y 28j", "my secret password")  # => hello this is my very secret string

我不介意它的加密或解密方式,我 只是想有办法做到这一点:),我也没有 注意它的输出,它可以是二进制的,一个对象, 一个字符串,任何东西

【问题讨论】:

    标签: python python-3.x encryption cryptography passwords


    【解决方案1】:

    基于the answer from Sam Hartzog,下面是一个示例,它遵循RFC8018, Section 6.2 中定义的 PBES2(基于密码的加密方案 2)描述的逻辑。但是,它缺少编码算法选择和参数。

    #!/usr/bin/python
    
    import base64
    import secrets
    from cryptography.fernet import Fernet
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
    
    KDF_ALGORITHM = hashes.SHA256()
    KDF_LENGTH = 32
    KDF_ITERATIONS = 120000
    
    def encrypt(plaintext: str, password: str) -> (bytes, bytes):
        # Derive a symmetric key using the passsword and a fresh random salt.
        salt = secrets.token_bytes(16)
        kdf = PBKDF2HMAC(
            algorithm=KDF_ALGORITHM, length=KDF_LENGTH, salt=salt,
            iterations=KDF_ITERATIONS)
        key = kdf.derive(password.encode("utf-8"))
    
        # Encrypt the message.
        f = Fernet(base64.urlsafe_b64encode(key))
        ciphertext = f.encrypt(plaintext.encode("utf-8"))
    
        return ciphertext, salt
    
    def decrypt(ciphertext: bytes, password: str, salt: bytes) -> str:
        # Derive the symmetric key using the password and provided salt.
        kdf = PBKDF2HMAC(
            algorithm=KDF_ALGORITHM, length=KDF_LENGTH, salt=salt,
            iterations=KDF_ITERATIONS)
        key = kdf.derive(password.encode("utf-8"))
    
        # Decrypt the message
        f = Fernet(base64.urlsafe_b64encode(key))
        plaintext = f.decrypt(ciphertext)
    
        return plaintext.decode("utf-8")
    
    def main():
        password = "aStrongPassword"
        message = "a secret message"
    
        encrypted, salt = encrypt(message, password)
        decrypted = decrypt(encrypted, password, salt)
    
        print(f"message: {message}")
        print(f"encrypted: {encrypted}")
        print(f"decrypted: {decrypted}")
    

    输出:

    message: a secret message
    encrypted: b'gAAAAABjDlH2eaRZmB4rduBdNHUOITV5q4oelpnLRUgI_uyQyNpUyW8h3c2lZYS1MwMpRWIZposcZvag9si1pc4IEK83_CzyBdXF27Aop9WWS6ybxTg9BSo='
    decrypted: a secret message
    

    【讨论】:

    【解决方案2】:

    稍加努力,密码学包 (pip install cryptography) 就可以很好地解决这个问题。我认为您看不到简单的 OOTB 的原因基于字符串实现是密码学在字节级别上工作,而不是字符串(可能以任何方式编码)。无论如何,以下内容似乎适用于您概述的简单用例。

    创建一个“加密器”并加密一些东西

    from cryptography.fernet import Fernet
    import base64
    entered_pw = "secretpw"
    key = base64.b64encode(f"{entered_pw:<32}".encode("utf-8"))
    encryptor = Fernet(key=key)
    encrypted = encryptor.encrypt(
        "my super secret data with a password".encode("utf-8")
    )
    print(encrypted)
    

    输出:

    b'gAAAAABjDVew9-VszAFP1ZdlDz-ZqwdIksCBhLbH8OEJjxEZyEy6cQ4jrxEBHZtHsGtWxHsG0qJIkQ_b5e5Ibx5-1uAa1HXdBwWys6YE7WwhmMPtAbj_VP2F8rKFck7MYvv5nKrZbWGF'

    使用正确输入的密码解密结果

    from cryptography.fernet import Fernet
    import base64
    entered_pw = "secretpw"
    key = base64.b64encode(f"{entered_pw:<32}".encode("utf-8"))
    encryptor = Fernet(key=key)
    encrypted = b'gAAAAABjDVew9-VszAFP1ZdlDz-ZqwdIksCBhLbH8OEJjxEZyEy6cQ4jrxEBHZtHsGtWxHsG0qJIkQ_b5e5Ibx5-1uAa1HXdBwWys6YE7WwhmMPtAbj_VP2F8rKFck7MYvv5nKrZbWGF'
    print(encryptor.decrypt(encrypted).decode("utf-8"))
    

    输出:

    'my super secret data with a password'

    如果您提供错误的在解密时输入密码,您将获得 InvalidSignature 异常。

    完全披露,我不是密码学专家,所以这可能是一个非常糟糕和不安全的方法,但它似乎是合法的¯_(ツ)_/¯。如果那里有任何加密专家想要带我去完成任务,请随意......;)

    【讨论】:

    • 您不应该使用密码本身作为对称加密的密钥,而是使用密钥派生函数来生成适当长度的伪随机密钥。
    • 谢谢,尽管@chuckx 对您的回答有所改进,但仍然感谢 :)
    【解决方案3】:

    尝试使用这个微型 python 模块作为密码学的包装器

    pip 安装 pyeasyencrypt

    代码示例:

    import logging, os
    # pip install pyeasyencrypt
    from pyeasyencrypt.pyeasyencrypt import encrypt_string, decrypt_string
    
    level = os.getenv("LOGGER", "INFO")
    logging.basicConfig(level=level)
    logger = logging.getLogger(__name__)
    
    def main():
        logger.info("Example")
        clear_string = 'stringA'
        password = "my password"
        encrypted_string = encrypt_string(clear_string, password)
        decrypted_string = decrypt_string(encrypted_string, password)
        logger.info(f"clear_string={clear_string} decrypted_string={decrypt_string} password={password}  encrypted_string={encrypted_string}")
        logger.debug("Done")
    
    if __name__ == '__main__':
        main()
    

    有关源代码的更多详细信息,请访问 github https://github.com/redcorjo/pyeasyencrypt

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多