【问题标题】:Using mysql AES encrypt and decrypt from Django从 Django 使用 mysql AES 加密和解密
【发布时间】:2018-10-03 12:50:47
【问题描述】:

在我的 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() 函数删除

【问题讨论】:

    标签: mysql django encryption aes pycrypto


    【解决方案1】:

    经过多次 google,我发现了这个 blog article 关于在 PHP 中复制 mysql AES 加密。
    他们的关键是用于填充的字符是具有等于 AES 块大小和文本长度之间的长度差的 ascii 代码的字符。

    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 加密相同的输出。

    【讨论】:

      【解决方案2】:

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

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

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-20
        • 2014-01-05
        • 2019-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-30
        • 1970-01-01
        相关资源
        最近更新 更多