【问题标题】:Is it possible to encrypt then decrypt data securely against a password in Python?是否可以根据 Python 中的密码安全地加密然后解密数据?
【发布时间】:2018-09-03 01:50:37
【问题描述】:

我在 python 程序中有一些数据,我想在使用密码写入文件之前对其进行加密,然后在使用之前读取并解密它。我正在寻找一些可以根据密码加密和解密的安全对称算法。

This question 显示了一种不安全的方式并建议使用 libsodium。由于我使用的是 Python,所以我找到了pysodium。它似乎有大量从 libsodium 映射的函数,但我不知道如何简单地根据密码加密/解密数据。

我的问题是,看起来所有加密算法都使用密钥。我不想使用钥匙。我想使用密码。就像我在终端中所做的那样:

加密:

$ cat data | openssl aes-256-cbc -salt | dd of=output.des3

解密:

$ dd if=output.des3 | openssl aes-256-cbc -d -salt

是否可以用 pysodium 做到这一点(以跨平台的方式,所以请不要建议使用系统调用)?

【问题讨论】:

  • 1.加密是基于数据的,这意味着 8 位字节,而不是字符,并且密钥需要是正确的长度。 2. 如果您想使用密码,您需要从不常用的方法派生密钥是加密哈希,并且为了安全,应该消耗约 100 毫秒的 CPU 时间,选择的方法是 PBKDF2。需要 CPU 刻录,因为通常密码不安全,它们是针对常用密码列表进行暴力破解的。 3. 3DES,不是 AES,真的吗?
  • @zaph 感谢您的回复。您对 AES 的看法是正确的。我正在切换到那个。我目前也在研究 PBKDF2。但与此同时,你为什么要区分字符和字节?解决这个问题不是我们只需要 ascii 吗?还有关于彩虹桌......嗯......这不是我们使用盐的原因吗?为什么即使加盐(必要时加胡椒)密码也不安全?如果我提出明显的问题,请原谅我对此事的无知。我错过了什么明显的东西吗?
  • @JamesKPolk 感谢您尝试提供帮助...由于某种原因,当我运行crypto_pwhash 时,我不断收到“不支持的版本”错误...不知道为什么或如何以及缺乏文档是真的恼人的。我正在做与我想做的完全相反的事情......我希望我能找到一些单线来加密我的数据和单线来解密它,但由于某种原因不存在。现在我正在处理 python 的密码学包......也许可以做到。
  • 如果您解决了您的问题,请发表您的答案
  • @IamTheWalrus 我现在正在考虑使用 Argon2 对我的密码进行哈希处理,然后将其用作密钥。我正在努力。

标签: python python-3.x encryption openssl


【解决方案1】:

所以我的问题简化为:“如何在 Python 中根据密码加密数据”。由于缺乏文档,我放弃了 pysodium。我使用cryptographyargon2 包来编写我自己的加密算法(这不是我自己的加密算法,我知道加密中的第一条规则;这只是利用已有内容的程序)。所以这是我的功能:

import cryptography.fernet
import argon2
import base64

def encrypt_data(data_bytes, password, salt):
    password_hash = argon2.argon2_hash(password=password, salt=salt)
    encoded_hash = base64.urlsafe_b64encode(password_hash[:32])
    encryptor = cryptography.fernet.Fernet(encoded_hash)
    return encryptor.encrypt(data_bytes)


def decrypt_data(cipher_bytes, password, salt):
    password_hash = argon2.argon2_hash(password=password, salt=salt)
    encoded_hash = base64.urlsafe_b64encode(password_hash[:32])
    decryptor = cryptography.fernet.Fernet(encoded_hash)
    return decryptor.decrypt(cipher_bytes)

下面是如何使用它们的示例:

cipher = encrypt_data("Hi Dude, Don't tell anyone I said Hi!".encode(), "SecretPassword", "SaltySaltySalt")
decrypted = decrypt_data(cipher, "SecretPassword", "SaltySaltySalt")
print(cipher)
print(decrypted.decode())

请记住,加密仅适用于字节;不适用于字符串。这就是我使用encode/decode的原因。

为什么是argon2?因为它是一种内存硬算法,很难用 GPU 和 ASIC 破解(是的,我是加密货币粉丝)。

为什么选择费内特?因为它使用了AES CBC,看起来足够安全;此外,它真的很容易使用(这正是我所需要的......我不是密码学家,所以我需要一个黑匣子才能使用)。

免责声明:请注意,我不是密码学家。我只是一个程序员。请随时批评我的加密和解密方式,并随时添加您的贡献以使其变得更好。

【讨论】:

  • 我不确定我是否理解您为什么要对 Argon2 的结果进行 base64 编码。我假设Fernet 的参数很可能是AES 密钥,是吗?如果是这样,你传递的字节太多了。
  • @LukeJoshuaPark Fernet 在该函数中占用的字节数不超过 32,所以我只是将其裁剪为 32。Fernet 通常将其自己的 generate_key() 静态方法的结果作为其键,我检查发现它使用b64encode编码一个随机数。所以我所做的只是我使用了相同的方式,除了输入是 Argon2 哈希,以确保哈希的可重复性而不是生成随机密钥。
  • @LukeJoshuaPark 我以前试过这个。它给出了错误:Fernet key must be 32 url-safe base64-encoded bytes.ValueError: Fernet key must be 32 url-safe base64-encoded bytes.。我不知道该怎么做。
  • 啊,好吧。这很奇怪。加密通常需要原始字节......奇怪的是,这需要一个 base-64 字符串。我想这就是适合你的 Python!
  • @IamTheWalrus 修剪哈希是密码学中的一种正常做法,并且没有任何不良副作用,除了从数学角度来看增加碰撞概率的明显且可忽略的事实。我看到这一直在做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-14
  • 2012-03-24
  • 1970-01-01
  • 2011-06-21
  • 2012-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多