Python AES编码/解码字符串并存储在MySQL中

标签 python mysql encryption pyramid pycrypto

我正在开发一个使用 Pyramid 1.3 (Python 2.7) 并将数据存储在 MySQL 中的项目。我有一个电子邮件地址表,我想对它们进行加密以进行存储。我试图在应用程序中加密它们,然后将它们解密以供查看。我不打算完全安全,但主要目的是在数据库本身受到损害时充分混淆数据。

我正在将 PyCrypto 与 AES 结合使用,并且一直在尝试关注此处的一些帖子和我发现的一些网络教程。到目前为止我发现的最接近的是 this post ,它似乎有效,至少加密了它。我遵循它并得到类似 "7hBAQrWhJRnL9YdBGJfRErGFwGi3aC6noGzYTrGwAoQ=" 的东西存储在数据库中。但是解密函数一直出错:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xa1 in position 1: ordinal not in range(128)

我遇到了一些关于 Python 的 unicode 演示文稿,这在某种程度上帮助我更好地理解了它,但我仍然不断遇到同样的错误。

是否有关于如何编码、存储在数据库中、从数据库中提取以及解码源数据字符串的简单教程?

我是否需要数据库列的特定排序规则?该字段是否需要是某种类型?到目前为止,我一直在使用默认排序规则并将其设置为 VARCHAR,假设我正在存储一个字符串。听起来我在某个地方遇到了不兼容类型或其他问题的编码问题,但我的头在我需要更改某些东西的地方旋转。

我可以提供任何更好的指示或其他任何东西吗?我可以展示我的代码,但它基本上是上面链接的副本......我只是想在修改太多之前让概念证明有效。

编辑: 一些样本来源... 在 MySQL 中,表是 编号(整数) client_id(整数) emailaddress varchar(100) utf8mb4_general_ci(我一直在研究归类,我不知道它应该是什么!)

python :

from base64 import b64encode, b64decode, urlsafe_b64decode, urlsafe_b64encode

BLOCK_SIZE = 32
INTERRUPT = u'\u0001'
PAD = u'\u0000'
def AddPadding(data, interrupt, pad, block_size):
    new_data = ''.join([data, interrupt])
    new_data_len = len(new_data)
    remaining_len = block_size - new_data_len
    to_pad_len = remaining_len % block_size
    pad_string = pad * to_pad_len
    return ''.join([new_data, pad_string])
def StripPadding(data, interrupt, pad):
    return data.rstrip(pad).rstrip(interrupt)#data.rsplit(interrupt,1)[0]#rstrip(pad).rstrip(interrupt)

SECRET_KEY = u'a1b2c3d4e5f6g7h8a1b2c3d4e5f6g7h8'
IV = u'12345678abcdefgh'

cipher_for_encryption = AES.new(SECRET_KEY, AES.MODE_CBC, IV)
cipher_for_decryption = AES.new(SECRET_KEY, AES.MODE_CBC, IV)

def EncryptWithAES(encrypt_cipher, plaintext_data):
    plaintext_padded = AddPadding(plaintext_data, INTERRUPT, PAD, BLOCK_SIZE)
    encrypted = encrypt_cipher.encrypt(plaintext_padded)
    return urlsafe_b64encode(encrypted)
def DecryptWithAES(decrypt_cipher, encrypted_data):
    decoded_encrypted_data = urlsafe_b64decode(encrypted_data)
    decrypted_data = decrypt_cipher.decrypt(decoded_encrypted_data)
    return StripPadding(decrypted_data, INTERRUPT, PAD)

#encrypts it
posted_singleaddress = EncryptWithAES(cipher_for_encryption, posted_singleaddress)

#"me@mail.com" inserts "Ktpr49Uzn99HZXbmqEzGKlWo9wk-XBMXGZl_iyna-8c=" into the database

clientemails 是上表中的电子邮件列表。取消注释时出现错误:

#if clientemails:
#    decrypted = DecryptWithAES(cipher_for_decryption, clientemails[0].emailaddress)

我只是想解码第一个项目,只是为了让它正常工作,但那部分似乎现在适合它......

最佳答案

PyCrypto 的一般规则是加密 key 、IV、明文、填充和密文应始终定义为二进制字符串,而不是文本。您为它们使用 Unicode 这一事实本身就是问题的根源。

另一个问题是您以十六进制编码形式传递给 AES.new key 和 IV,因此前者为 256 位,后者为 128 位。这似乎仍然有效,但我猜你的意图是使用 AES128 - 它有一个 128 位 key 。因此,您需要将其转换为二进制,例如通过 unhexlify:两个字符串 b'34' 将映射到单个字节 '\x34'。 IV 需要两倍长。

因此在您的代码中最好有:

from binascii import unhexlify

INTERRUPT = b'\x01'
PAD = b'\x00'
SECRET_KEY = unhexlify('a1b2c3d4e5f6g7h8a1b2c3d4e5f6g7h8')
IV = unhexlify('12345678abcdefgh'*2)

如果您需要加密文本,您首先要对其进行编码(例如编码为 UTF-8),然后将其传递给您的函数 EncryptWithAES()。另请参阅取自 PyCrypto API 的示例:

from Crypto.Cipher import AES
from Crypto import Random

key = b'Sixteen byte key'
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CFB, iv)
msg = iv + cipher.encrypt(b'Attack at dawn')

加密步骤的结果(即密文)又是一个二进制字符串。为了将其直接存储在 MySQL 数据库中,您必须使用 BINARYVARBINARY 类型的列。

关于Python AES编码/解码字符串并存储在MySQL中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10763182/

相关文章:

linux - 从远程转储文件恢复 mysql 数据库

java - 获取异常 java.security.InvalidKeyException : Invalid AES key length: 29 bytes?

python - 未成功追加到空 NumPy 数组

两个类之间的python线程无法正常工作

Python嵌套列表和递归问题

java - 即使输入相同,AES/CBC/NoPadding 是否会生成两个不同的密文?

c - 平台间加密结果不同,使用OpenSSL

Python - 数组的最大值

mysql - 如何使用 "order by if"为查询索引表?

php - 不正确的整数值 SQL 错误