Python上的AES256:多重传递错误?

Python上的AES256:多重传递错误?,python,encryption,encoding,utf-8,aes,Python,Encryption,Encoding,Utf 8,Aes,我在Python中使用AES256加密进行多次加密时遇到问题 以下是我迄今为止一直在使用的函数: 加密: def AESEncrypt(plaintext, password, passes = 1): try: salt = Random.get_random_bytes(32) iv = Random.get_random_bytes(16) hmacsha256 = get_prf("hmac-sha256") ke

我在Python中使用AES256加密进行多次加密时遇到问题

以下是我迄今为止一直在使用的函数:

加密:

def AESEncrypt(plaintext, password, passes = 1):
    try:
        salt = Random.get_random_bytes(32)
        iv = Random.get_random_bytes(16)

        hmacsha256 = get_prf("hmac-sha256")
        key = KDF.PBKDF2(password, salt, 32, 4096, hmacsha256[0])

        aesManaged = AES.new(key, AES.MODE_CBC,iv)

        padlength = 0
        padByte = chr(0)
        if len(plaintext) < 16:
            padlength = 16 - len(plaintext)
            padByte = chr(padlength)
        else:
            padlength = 16 - (len(plaintext) % 16)
            padByte = chr(padlength)    
            for i in range(padlength):
                plaintext = plaintext + b"\x00"
        countByte = chr(passes)
        if passes == 1:
            ciphertext = countByte + padByte + iv + salt + aesManaged.encrypt(plaintext)
    elif passes >= 2:
        ciphertext = aesManaged.encrypt(plaintext)
            for i in range(passes - 1):
                ciphertext = aesManaged.encrypt(ciphertext)
                ciphertext = countByte + padByte + iv + salt + ciphertext
    return ciphertext
except:
    print str(sys.exc_info()[1])
    return None
def AESDecrypt(ciphertext, password):
    try:
        base_cipher = ciphertext

        passes = ord(base_cipher[0])
        padLength = ord(base_cipher[1])
        iv = base_cipher[2:18]
        salt = base_cipher[18:50]
        hmacsha256 = get_prf("hmac-sha256")
        key = KDF.PBKDF2(password, salt, 32, 4096, hmacsha256[0])
        aesManaged = AES.new(key, AES.MODE_CBC,iv)

        msg_cipher = base_cipher[50:]

        if passes == 1:
            plaintext_bytes = aesManaged.decrypt(msg_cipher)
        elif passes >= 2:
            plaintext_bytes = aesManaged.decrypt(msg_cipher)
            for i in range(passes - 1):
                plaintext_bytes = aesManaged.decrypt(plaintext_bytes)

        if padLength > 0:
            ptLength = len(plaintext_bytes)
            plaintext_bytes = plaintext_bytes[:ptLength - padLength]
        return plaintext_bytes
    except:
        print str(sys.exc_info()[1])
        return None
就写二进制数据而言,它可以很好地使用单通道和多通道加密。当涉及到加密文本数据(如文本文件或消息)时,当我在解密时使用
传递的
值大于1时,它就开始出错

例如,如果我在上述过程或UTF-16中仅使用纯文本,如
“Hello World!”
,则多通道加密将为我提供一堆损坏的文本(最多使消息的一半乱码),其余消息将正确解密

当我使用UTF-8编码,如
“Hello World.encode('UTF-8')
时,同样使用相同的过程,我会得到一个错误,即(尽管每次运行时字节数和位置都会发生变化):

“utf8”编解码器无法解码位置0中的字节0xf7:无效的开始字节

是不是我做错了什么

更新:

def AESEncrypt(plaintext, password, passes = 1):
    try:
        salt = Random.get_random_bytes(32)
        iv = Random.get_random_bytes(16)

        hmacsha256 = get_prf("hmac-sha256")
        key = KDF.PBKDF2(password, salt, 32, 4096, hmacsha256[0])

        aesManaged = AES.new(key, AES.MODE_CBC,iv)

        padlength = 0
        padByte = chr(0)
        if len(plaintext) < 16:
            padlength = 16 - len(plaintext)
            padByte = chr(padlength)
        else:
            padlength = 16 - (len(plaintext) % 16)
            padByte = chr(padlength)    
            for i in range(padlength):
                plaintext = plaintext + b"\x00"
        countByte = chr(passes)
        if passes == 1:
            ciphertext = countByte + padByte + iv + salt + aesManaged.encrypt(plaintext)
    elif passes >= 2:
        ciphertext = aesManaged.encrypt(plaintext)
            for i in range(passes - 1):
                ciphertext = aesManaged.encrypt(ciphertext)
                ciphertext = countByte + padByte + iv + salt + ciphertext
    return ciphertext
except:
    print str(sys.exc_info()[1])
    return None
def AESDecrypt(ciphertext, password):
    try:
        base_cipher = ciphertext

        passes = ord(base_cipher[0])
        padLength = ord(base_cipher[1])
        iv = base_cipher[2:18]
        salt = base_cipher[18:50]
        hmacsha256 = get_prf("hmac-sha256")
        key = KDF.PBKDF2(password, salt, 32, 4096, hmacsha256[0])
        aesManaged = AES.new(key, AES.MODE_CBC,iv)

        msg_cipher = base_cipher[50:]

        if passes == 1:
            plaintext_bytes = aesManaged.decrypt(msg_cipher)
        elif passes >= 2:
            plaintext_bytes = aesManaged.decrypt(msg_cipher)
            for i in range(passes - 1):
                plaintext_bytes = aesManaged.decrypt(plaintext_bytes)

        if padLength > 0:
            ptLength = len(plaintext_bytes)
            plaintext_bytes = plaintext_bytes[:ptLength - padLength]
        return plaintext_bytes
    except:
        print str(sys.exc_info()[1])
        return None
在查看了Python文档中的
字节
字节数组
类型后,我尝试转换应被视为字节数组的部分:

(我计划在获得正确的加密后进行解密和类型检测部分)

def AESENSCRYPT(明文、密码、密码=1):
尝试:
纯文本=字节数组(纯文本)
salt=字节(随机。获取随机字节(32))
iv=字节(随机。获取随机字节(16))
hmacsha256=获取prf(“hmac-sha256”)
key=KDF.PBKDF2(密码,salt,324096,hmacsha256[0])
AES管理=AES.新建(键,AES.模式\u CBC,iv)
焊盘长度=0
padByte=chr(0)
如果len(纯文本)<16:
焊盘长度=16-长度(纯文本)
padByte=chr(焊盘长度)
其他:
padlength=16-(长度(明文)%16)
padByte=chr(焊盘长度)
对于范围内的i(焊盘长度):
纯文本。附加(b“\x00”)
countByte=chr(通过)
如果通过==1:
密文=字节(countByte+padByte+iv+salt+aesManaged.encrypt(明文))
elif通过次数>=2:
密文=bytearray(AES托管.加密(明文))
对于范围内的i(通过-1):
ciphertext=aesManaged.encrypt(密文)
密文插入(0,salt)
密文插入(0,iv)
密文插入(0,padByte)
密文.插入(0,countByte)
返回密文
除:
打印“第%d行错误:%s”%(sys.exc\u traceback.tb\u行号,str(sys.exc\u info()[1]))
一无所获

现在我得到的是
参数必须是字符串或只读缓冲区,而不是bytearray
错误,这些错误应该是字节数组,但要求字符串。在当前示例中,它位于
elif passs>=2
之后的一行,将密文转换为字节数组。

至少存在两个问题:

  • sys.getdefaultencoding()
    在Python2环境中返回
    utf-8
    ,而不是
    ascii
    。它可能会在某些输入上以静默方式中断某些Python库。这是一种创建难以调试的数据相关bug的方法。在
    站点
    站点自定义
    用户自定义
    模块中查找
    sys.setdefaultencoding

  • bytestring.encode('utf-8')
    相当于
    bytestring.decode(sys.getdefaultencodeding()).encode('utf-8')
    。不要在bytestring上调用
    .encode(char\u encoding)
    ,而是在Unicode字符串上使用它

  • 不要混合使用字节和Unicode字符串。为简单起见,从只处理字节的API开始,即拒绝Unicode字符串,并确保代码不会意外返回它们(这适用于加密/解密方法)


    bytearray()
    是一个可变的字节序列。您几乎可以在
    字节
    (不可变的字节序列)或(更一般地)任何支持的对象可以使用的任何地方使用它

    似乎
    aesManaged.encrypt(明文)
    plaintext
    是字节数组时引发异常。除了可以用基于
    .rjust
    的代码替换的
    .append
    调用之外,您的代码不会在原地修改
    明文。直到
    AES
    模块更新为支持
    bytearray
    ;在这种情况下,不要使用
    bytearray
    ,也不要在将其传递给不直接支持
    bytearray
    AES
    方法之前对其进行转换(尝试
    buffer(明文)


    代码中存在不必要的类型转换。删除它们。

    当你说“仅适用于字节”时,这正是我的想法——我希望我的函数能够加密/解密字节。但是如何将Unicode字符串转换为字节数组?@ki2ne:
    bytestring=Unicode\u string.encode(character\u encoding)
    在查找Python文档后,我可以使用
    bytearray
    类型(并使用
    bytearray()
    转换字符串)为了避免混淆和/或混淆字符串和字节数组?@ki2ne:
    bytearray()
    只是一个可变的字节序列。您几乎可以在任何可以使用
    字节的地方使用它。
    参数必须是字符串或只读缓冲区,而不是bytearray