使用mysql AES加密和解密Django

时间:2018-04-23 12:57:01

标签: mysql django encryption aes pycrypto

在我的Django应用程序中,我想使用mysql数据库中的AES_ENCRYPTAES_DECRYPT来加密和解密内容。
我知道python的Crypto包有AES支持,但Crypto AES不会产生与mysql AES相同的结果,尽管我确保两者都使用ECB模式。
所以,现在我这样做了:

sql = "select 1 as id, AES_ENCRYPT(my_field, '16-bytes encryption key') as field_enc from appname_table"
encrypted_fields = MyModel.objects.raw(sql)

这使我获得加密后的字段值,并且工作正常。问题是AES算法加密最终结果有许多不可打印的字符,它看起来像这样:

encrypted_fields[3].field_enc
'\x88\xc5\xe4\xa0c?\xf8\x16|^1JB\x83{\xdf'
print(encrypted_fields[3].field_enc)
���c?�|^1JB�{�

所以,现在当我尝试使用相同的值来解密它时,mysql会回复一个错误,上面写着

  

“OperationalError:(1300,”无效的utf8字符串:   '\ X88 \ XC5 \ XE4 \ xA0c' “)”

我想这是因为我试图将不可打印的字符发送到mysql查询。

那么,我该怎么做呢? 请注意,我必须使用MySQL函数,因为我使用这些函数加密了一些数据库字段,因此我需要使用相同的函数对它们进行解密,因为Crypto的AES不会得到相同的结果。 Crypto一直要求加密的文本必须像密钥一样长16个字节,而mysql不需要。

我还试图看看mysql在加密之前是否对文本使用了某种填充,但它没有说明它们在webpage上填充了哪些字符:

  

str和crypt_str参数可以是任意长度,填充是   自动添加到str,因此它是所需的块的倍数   通过基于块的算法,如AES。这个填充是自动的   由AES_DECRYPT()函数删除

2 个答案:

答案 0 :(得分:0)

在许多谷歌之后,我发现这个blog article关于在PHP中复制mysql AES加密。
它们的关键结果是用于填充的字符是具有ascii代码的字符,该代码等于AES块大小和文本长度之间的长度差异。

c = chr(16 - len(text_to_be_encrypted))
def align_str(s, n, char):
    if len(s) < n:
        diff = n - len(s)
        for i in range(diff):
            s += char
    return s
s = align_str(text_to_be_encrypted, 16, c)
e = encryption_suite.encrypt(s)

它有效。它产生与mysql加密相同的输出。

答案 1 :(得分:0)

在这篇关于在 PHP 中复制 mysql AES 加密的 article 中,我发现 mysql 使用 ECB 模式进行 AES 加密。 Pycrypto 库为 AES 加密提供了 ECB 模式。根据 pycrypto documentation 关于 ECB,输入必须与右边界对齐,并且其大小必须是 block_size 的倍数(即 AES 为 16 字节)。 pycryptodome 库“pad”中的一个函数在这里起到了作用,但它需要字节串作为输入。

下面提供的代码在 python 语言中给出了与 mysql 对应的相同的 AES 加密结果。

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
def aes_encrypt(data):
    key = b'1234567812345678' # 16 byte key
    obj = AES.new(key, AES.MODE_ECB)
    padded_data = pad(bytes(data,'utf-8'),16)   
    encrypted_data = obj.encrypt(padded_data)
    return encrypted_data