10

我正在尝试在 python 中加密和解密文本,我知道该怎么做 - 问题是我不想使用一定数量的字母,如 16 或 32。我希望能够使用尽可能多的字母/数字,然后加密文本没有任何错误。

python中的base64是完美的,因为我可以做到这一点,但是当我想做的时候:

password = "password"
encode = base64.b64encode(password)

...它返回一个错误,因为它不是字节;它必须是这样的:

encode = base64.b64encode(b'password')

这完全没问题,但我不想那样做。

import base64

password = "hello world"  
encoded = base64.b64encode(password.encode("utf-8"))
print(encoded)
decoded = base64.b64decode(encoded)
print(decoded)

那现在是我的代码,它工作正常,但我现在知道我使用了错误类型的东西,我需要知道如何使用 AES。

4

1 回答 1

28

在 Python 3 中,您需要将字符串转换为字节,因为 base64 编码取决于字符串的编码,而 Python 3 不对字符串编码做出假设。看到这个问题

import base64

# Assuming UTF-8 encoding, change to something else if you need to
base64.b64encode("password".encode("utf-8"))

本页解释了为什么字符串在 Python 3 中的行为不同:

与 2.x 情况的最大区别在于,任何在 Python 3.0 中混合文本和数据的尝试都会引发 TypeError,而如果您要在 Python 2.x 中混合 Unicode 和 8 位字符串,如果 8 位string 恰好只包含 7 位 (ASCII) 字节,但如果它包含非 ASCII 值,您会得到 UnicodeDecodeError。多年来,这种特定于价值的行为引起了许多悲伤的面孔。

而且,就像 sberry 所说,base64 编码不是加密。如果您确实希望它是安全的,则需要使用 AES 之类的东西,或者如果您只想安全地存储密码,请使用 bcrypt 或 PBKDF2。


这是使用 PyCrypto使用 AES加密某些内容的示例,使用从使用 PBKDF2的密码派生的密钥。

#!/usr/bin/env python3

from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Protocol.KDF import PBKDF2

def make_key(password, salt = None):
    if salt is None:
        # Generate a key from the password
        salt = Random.new().read(8)

    # You probably want to adjust the number of iterations
    # based on your target platform and willingness to wait.
    # Somewhere around 10,000 will give you reasonable security.
    # If you don't mind the wait, 100,000 is better.
    # If you have a really fast computer, or are willing to wait a long
    # time, feel free to set it even higher.
    key = PBKDF2(password, salt, AES.block_size, 100000)
    return (key, salt)

def encrypt(message, key):
    # The IV should always be random
    iv = Random.new().read(AES.block_size)
    cipher = AES.new(key, AES.MODE_CFB, iv)
    ciphertext = cipher.encrypt(message.encode("utf-8"))
    return (ciphertext, iv)

def decrypt(ciphertext, key, iv):
    cipher = AES.new(key, AES.MODE_CFB, iv)
    msg = cipher.decrypt(ciphertext).decode("utf-8")
    return msg

def main():
    # Encryption
    password = "correct horse battery staple"
    message = "Super secret information that shouldn't be seen by attackers"
    key, salt = make_key(password)
    ciphertext, iv = encrypt(message, key)
    print(b"The ciphertext is: " + ciphertext)

    # Decryption

    # In normal cases, you now need to store the salt and iv somewhere
    # Usually you prepend them to the ciphertext
    # I don't feel like doing that, so we'll just assume that I got the salt
    # and IV somehow.
    key, _ = make_key(password, salt)
    cleartext = decrypt(ciphertext, key, iv)
    print("The cleartext is: " + cleartext)

if __name__ == "__main__":
    main()

像这样使用 AES 提供机密性(攻击者在没有密码的情况下无法读取消息),但不提供完整性(攻击者可以将数据插入密文,而您可以注意到的唯一方法是它可能会解密为垃圾) . 为了防止这种情况,您还可以使用消息验证码来确保密文没有被没有密码的人更改。


我认为这是一个有趣的练习,所以我在BitBucket repo中放了一个更完整的示例。它添加了一个 HMAC,并从 JSON 文件中读取和写入。

于 2013-05-24T17:15:06.397 回答