AES使用Pycrypto Python异常解密:“内置”。UnicodeDecodeError:“utf-8”编解码器在0位置无法解码字节0x80:开始字节无效”

时间:2023-01-04 20:43:56

I am using following implementation of AES cipher :-

我正在使用以下AES密码实现:-

import hashlib
from Crypto.Cipher import AES

class AESCipher:
    def __init__(self, key):
        self.BS = 128
        try:
            self.key = hashlib.sha256(key.encode()).digest()[:self.BS]
        except:
            self.key = hashlib.sha256(key).digest()[:self.BS]
        self.iv = Random.new().read(AES.block_size)
    def encrypt(self, raw):
        raw = self._pad(raw)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return base64.b64encode(self.iv + cipher.encrypt(raw))
    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        self.iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode()
    def _pad(self, s):
        return s + (self.BS - len(s) % self.BS) * chr(self.BS - len(s) % self.BS).encode()
    @staticmethod
    def _unpad(s):
        return s[:-ord(s[len(s)-1:])]

Encryption for a binary encoded dictionary object causes no errors but when I try to decrypt the same encrypted object, following exception is raised :-

二进制编码字典对象的加密不会导致任何错误,但是当我尝试解密相同的加密对象时,会引发以下异常:-

return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode()
builtins.UnicodeDecodeError: 'utf-8' codec can't decode byte 0x80 in position 0: invalid start byte

I tried to use 'ISO' and 'latin' encoding and decoding functions. But after that the socket on other side of the LAN recognizes it as a string and not as a dictionary object.

我尝试使用“ISO”和“latin”编码和解码功能。但在此之后,LAN另一端的套接字将它识别为字符串,而不是dictionary对象。

My question :- What I am doing wrong here ?

我的问题是:-我哪里做错了?

Additional information :-

附加信息:-

key = 'SHSJDS-DSJBSJDS-DSKNDS' # some thing following this pattern

bin_json_object = pickle.dumps(dict_object)
enc_json_object = AESenc(bin_json_object, key)

def AESenc(self, data, key):
    return AESCipher(key).encrypt(data)

def AESdec(self, data, key):
    return AESCipher(key).decrypt(data)

For example If I use "ISO-8859-1" encoding in the above code :-

例如,如果我在上面的代码中使用“ISO-8859-1”编码:-

binary encoded representation of dictionary object :-

字典对象的二进制编码表示:-。

b'\x80\x03}q\x00(X\x02\x00\x00\x00idq\x01X$\x00\x00\x0096e09f6c-1e80-4cd1-9225-159e35bcacb4q\x02X\x0c\x00\x00\x00request_codeq\x03K\x01X\x0e\x00\x00\x00payload_lengthq\x04K!X\x0b\x00\x00\x00session_keyq\x05Nu.'

encrypted representation of binary encoded dictionary object :-

二进制编码字典对象的加密表示:-

 b'cZi+L4Wi51B5oDGQKlFb9bioxKH3TFRO1piECklafwTe6GYm/VeVjJaCDKiI+o6f6CcUnMvx+2EfEwcHCH/KDDeHTivIUou7WGVrd1P++HxfYNutY/aOn30Y/yiICvwWRHBn/3zU3xXvr/4XrtoVddM2cQEgXupIcC99TIxurrr8CCZd74ZnWj6QB8quCtHD'

But if I now try to decrypt the same on other node on same LAN via socket. I get following decrypted representation :-

但是如果我现在尝试通过套接字在同一局域网的其他节点上解密同一个节点。我得到以下解密的表示:-

}q(XidqX$96e09f6c-1e80-4cd1-9225-159e35bcacb4qX
                                                              request_codeqKXpayload_lengthqK!X
                  session_keyqNu.

which is completely different from original binary representation of the same dictionary object. And produces the following exception :-

它与相同字典对象的原始二进制表示完全不同。并产生以下例外:-

data = pickle.loads(data)
builtins.TypeError: 'str' does not support the buffer interface

1 个解决方案

#1


0  

Finally after hours of debugging I came with a working code, but I am not able to understand, why this is working. Please if someone could explain this in comments. Modified version AES cipher code :-

经过几个小时的调试之后,我终于得到了一个可用的代码,但是我不能理解为什么它会工作。如果有人能在评论中解释一下。修改版本AES密码:-。

class AESCipher:
    def __init__(self, key):
        self.BS = AES.block_size
        try:
            self.key = hashlib.sha256(key.encode('ISO-8859-1')).digest()[:self.BS]
        except:
            self.key = hashlib.sha256(key).digest()[:self.BS]
        self.iv = Random.new().read(AES.block_size)
    def encrypt(self, raw):
        raw = self._pad(raw)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return base64.b64encode(self.iv + cipher.encrypt(raw))
    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        self.iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('ISO-8859-1')
    def _pad(self, s):
        return s + (self.BS - len(s) % self.BS) * chr(self.BS - len(s) % self.BS).encode('ISO-8859-1')
    @staticmethod
    def _unpad(s):
        print('returning : ', s[:-ord(s[len(s)-1:])])
        return s[:-ord(s[len(s)-1:])]

Now without modifying the AES encryption and decryption functions. I introduced a following variation in the code. Whenever another node receives a binary stream it first decrypts it with the AES decrypt function. But after decryption encoded dictionary object has to be encoded again with 'ISO-8859-1' as shown below :-

现在不需要修改AES加密和解密函数。我在代码中引入了以下变体。每当另一个节点接收到二进制流时,它首先使用AES解密函数对其进行解密。但是,在解密编码的dictionary对象之后,必须再次编码为“ISO-8859-1”,如下所示:

dict_object = self.AESdecryption(binary_stream, self.session_key)
dict = pickle.loads(dict_object.encode('ISO-8859-1'))
print(dict)

The above produces correct dictionary object. But what I don't understand is when a dictionary object was encrypted in 'ISO-8859-1' encoding, and and then decrypted on other node in 'ISO-8859-1' encoding, then why before passing it to the pickle.loads() I have to encode it again to get the original dictionary object. Please if someone could explain why it is happening ?

上述方法生成正确的字典对象。但我不理解的是,当一个dictionary对象被加密为“ISO-8859-1”编码,然后在“ISO-8859-1”编码中的其他节点上解密时,为什么在将其传递给pickle.load()之前,我必须再次对其进行编码,以获得原始的dictionary对象。如果有人能解释一下为什么会这样?

#1


0  

Finally after hours of debugging I came with a working code, but I am not able to understand, why this is working. Please if someone could explain this in comments. Modified version AES cipher code :-

经过几个小时的调试之后,我终于得到了一个可用的代码,但是我不能理解为什么它会工作。如果有人能在评论中解释一下。修改版本AES密码:-。

class AESCipher:
    def __init__(self, key):
        self.BS = AES.block_size
        try:
            self.key = hashlib.sha256(key.encode('ISO-8859-1')).digest()[:self.BS]
        except:
            self.key = hashlib.sha256(key).digest()[:self.BS]
        self.iv = Random.new().read(AES.block_size)
    def encrypt(self, raw):
        raw = self._pad(raw)
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return base64.b64encode(self.iv + cipher.encrypt(raw))
    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        self.iv = enc[:AES.block_size]
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('ISO-8859-1')
    def _pad(self, s):
        return s + (self.BS - len(s) % self.BS) * chr(self.BS - len(s) % self.BS).encode('ISO-8859-1')
    @staticmethod
    def _unpad(s):
        print('returning : ', s[:-ord(s[len(s)-1:])])
        return s[:-ord(s[len(s)-1:])]

Now without modifying the AES encryption and decryption functions. I introduced a following variation in the code. Whenever another node receives a binary stream it first decrypts it with the AES decrypt function. But after decryption encoded dictionary object has to be encoded again with 'ISO-8859-1' as shown below :-

现在不需要修改AES加密和解密函数。我在代码中引入了以下变体。每当另一个节点接收到二进制流时,它首先使用AES解密函数对其进行解密。但是,在解密编码的dictionary对象之后,必须再次编码为“ISO-8859-1”,如下所示:

dict_object = self.AESdecryption(binary_stream, self.session_key)
dict = pickle.loads(dict_object.encode('ISO-8859-1'))
print(dict)

The above produces correct dictionary object. But what I don't understand is when a dictionary object was encrypted in 'ISO-8859-1' encoding, and and then decrypted on other node in 'ISO-8859-1' encoding, then why before passing it to the pickle.loads() I have to encode it again to get the original dictionary object. Please if someone could explain why it is happening ?

上述方法生成正确的字典对象。但我不理解的是,当一个dictionary对象被加密为“ISO-8859-1”编码,然后在“ISO-8859-1”编码中的其他节点上解密时,为什么在将其传递给pickle.load()之前,我必须再次对其进行编码,以获得原始的dictionary对象。如果有人能解释一下为什么会这样?