当前位置: 代码迷 >> python >> Python上的AES256:多次通过错误?
  详细解决方案

Python上的AES256:多次通过错误?

热度:43   发布时间:2023-07-14 09:52:06.0

我在使用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的passes值时,它会开始出错。

例如,如果我只使用纯文本,例如"Hello World!" 使用上述步骤或使用UTF-16,多遍加密将给我一堆损坏的文本(最多显示一半的消息),其余的消息则被正确解密。

当我也使用UTF-8编码(例如"Hello World".encode('utf-8')进行相同的过程时,会收到一条错误消息(尽管每次运行时字节数和位置都会改变):

'utf8'编解码器无法解码位置0的字节0xf7:无效的起始字节

我做错了吗?

更新:

看Python文档为后bytesbytearray的类型,我试图转换应该被认为是一个字节数组的部分:

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

def AESEncrypt(plaintext, password, passes = 1):
    try:
        plaintext = bytearray(plaintext)
        salt = bytes(Random.get_random_bytes(32))
        iv = bytes(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.append(b"\x00")
        countByte = chr(passes)
        if passes == 1:
            ciphertext = bytes(countByte + padByte + iv + salt + aesManaged.encrypt(plaintext))
        elif passes >= 2:
            ciphertext = bytearray(aesManaged.encrypt(plaintext))
        for i in range(passes - 1):
            ciphertext = aesManaged.encrypt(ciphertext)
        ciphertext.insert(0, salt)
        ciphertext.insert(0, iv)
        ciphertext.insert(0, padByte)
        ciphertext.insert(0, countByte)
        return ciphertext
    except:
        print "Error on line %d: %s" % (sys.exc_traceback.tb_lineno, str(sys.exc_info()[1]))
        return None

现在,我只是想知道argument must be string or read-only buffer, not bytearray应该为字节数组但要求输入字符串的部分的字节数组错误。 在当前示例中,它在elif passes >=2之后的行中将密文转换为字节数组。

至少有两个问题:

  1. sys.getdefaultencoding()在您的Python 2环境中返回utf-8而不是ascii 它可能会无声地破坏某些输入上的某些Python库。 这是一种创建难以调试的数据相关错误的方法。 寻找sys.setdefaultencodingsitesitecustomizeusercustomize模块

  2. bytestring.encode('utf-8')等效于bytestring.decode(sys.getdefaultencoding()).encode('utf-8') 不要在字节字符串上调用.encode(char_encoding) ,而应在Unicode字符串上使用它。

不要混合字节和Unicode字符串。 为简单起见,从仅适用于字节的API开始,即拒绝Unicode字符串,并确保您的代码不会偶然返回(适用于加密/解密方法)。


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

plaintextaesManaged.encrypt(plaintext) ,似乎aesManaged.encrypt(plaintext)引发异常。 除了可以用基于.rjust的代码替换的.append调用之外,您的代码不会就地修改plaintext 直到AES模块更新为支持bytearray ; 在这种情况下,请勿使用bytearray或对其进行转换(尝试buffer(plaintext) ),然后再将其传递给不直接支持bytearray AES方法。

您的代码中没有不必要的类型转换。 删除它们。