我正在尝试用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时使用了错误的类型。
最佳答案
在python 3中,您需要将字符串转换为字节,因为base64编码依赖于字符串的编码,而python3不假设字符串编码。请参见this question。
import base64
# Assuming UTF-8 encoding, change to something else if you need to
base64.b64encode("password".encode("utf-8"))
This page解释为什么字符串在python 3中的作用不同:
与2.x情况的最大区别是,在python 3.0中,任何尝试混合文本和数据的操作都会引发类型错误,而如果在python 2.x中混合使用unicode和8位字符串,那么如果8位字符串恰好只包含7位(ascii)字节,那么它将起作用,但您将获得unicodedecode如果包含非ASCII值,则返回rror。这些年来,这种特定于价值的行为已经引起了无数的悲伤。
而且,正如斯贝里所说,base64编码不是加密。如果您真的希望这是安全的,您将需要使用像AES之类的东西,或者如果您只是想安全地存储密码,请使用bcrypt或pbkdf2。
下面是一个使用pycrypto加密某些内容的示例,使用从密码派生的密钥。
#!/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就可以提供with AES(攻击者无法在没有密码的情况下读取消息),但不能提供using PBKDF2(攻击者可以将数据插入到密文中,而您可以注意到的唯一方法是,它可能会作为垃圾进行解密)。为了防止这种情况发生,您还可以使用confidentiality来确保没有密码的人更改了密文。
我认为这是一个有趣的练习,所以我在integrity中举了一个更完整的例子。它添加了一个HMAC,并从JSON文件读取和写入。