Python base64.b64 编码错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16740188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 23:30:48  来源:igfitidea点击:

base64.b64encode error

pythonpython-3.x

提问by user2387537

I'm trying to encrypt and decrypt text in python, and I know how to do that - the problem is that I don't want to have to use a set amount of letters like 16 or 32. I want to be able to use as many letters/numbers as I want, and then encrypt the text without any errors.

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

base64 in python would be perfect, because I can do just that, but when I want to do:

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

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

... it returns an error because it's not in bytes; it has to be like:

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

encode = base64.b64encode(b'password')

That works completely fine, but I don't want to do that.

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

import base64

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

that is now my code and it works fine but i now know i was using the wrong type of thing i need to know on how to use AES.

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

采纳答案by Brendan Long

In Python 3, you need to convert your string to bytes, since base64 encoding depends on the encoding of the string, and Python 3 doesn't make assumptions about string encoding. See this question.

在 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"))

This pageexplains why strings act differently in Python 3:

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

The biggest difference with the 2.x situation is that any attempt to mix text and data in Python 3.0 raises TypeError, whereas if you were to mix Unicode and 8-bit strings in Python 2.x, it would work if the 8-bit string happened to contain only 7-bit (ASCII) bytes, but you would get UnicodeDecodeError if it contained non-ASCII values. This value-specific behavior has caused numerous sad faces over the years.

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

And, like sberry said, base64 encoding is not encryption. If you actually want this to be secure, you'll need to use something like AES, or if you just want to safely store the password, use bcrypt or PBKDF2.

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



Here's an example of using PyCrypto to encrypt something with AES, using a key derived from a password using 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()

Just using AES like this provides confidentiality(an attacker can't read the message without the password), but not integrity(an attacker couldinsert data into the ciphertext, and the only way you could notice is that it would probably decrypt as garbage). To prevent that, you can also use a message authentication codeto ensure that the ciphertext hasn't been changed by someone who doesn't have the password.

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



I thought this was an interesting exercise, so I put a more complete example in a BitBucket repo. It adds an HMAC, and reads and writes from a JSON file.

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