2016-02-11 42 views
1

我使用下面的實現AES加密的: -AES解密使用Pycrypto Python異常: 'builtins.UnicodeDecodeError: 'UTF-8' 的位置0編解碼器不能解碼字節0x80的:無效的起始字節'

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:])] 

加密的編碼字典對象二進制導致沒有錯誤,但是當我嘗試解密相同的加密的物體,以下異常引發: -

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 

我試圖用「ISO」和「拉丁」編碼和解碼功能。但是之後,局域網另一端的套接字將其識別爲字符串,而不是字典對象。

我的問題: - 我在這裏做錯了什麼?

附加信息: -

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) 

例如如果使用 「ISO-8859-1」 編碼在上面的代碼: -

二進制編碼字典對象的表示: -

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.' 

二進制編碼字典對象的加密表示: -

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

但是,如果我現在嘗試通過套接字解密在同一局域網上的其他節點上的相同。我獲得以下解密表示: -

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

這是來自同一字典對象的原始二進制表示完全不同。併產生以下異常: -

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

您能否提供您用於測試的代碼? – FBidu

+0

@FBidu添加了必要的代碼.. –

+0

你是什麼意思你嘗試過'ISO'和'拉丁',它應該是'decode(「ISO-8859-1」)'.. –

回答

0

最後調試小時後我有一個工作代碼來了,但我無法理解,爲什麼這是工作。如果有人可以在評論中解釋這個問題。 修改版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:])] 

現在無需修改AES加密和解密功能。我在代碼中引入了以下變體。每當另一個節點收到一個二進制流時,它首先使用AES解密函數對其進行解密。但經過解密編碼字典對象必須與「ISO-8859-1」再次編碼,如下所示: -

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

上面產生正確字典對象。但是我不明白的是,當字典對象以'ISO-8859-1'編碼進行加密,然後在'ISO-8859-1'編碼的其他節點上進行解密時,爲什麼在將其傳遞給pickle之前爲什麼。加載()我必須再次編碼它以獲得原始字典對象。如果有人能解釋爲什麼它會發生?

+0

這更多的是字符串表示形式爲二進制字符的問題;如果你將它們編碼爲「十六進制」,你可能會爲自己節省一些步驟。不管那個Python通常只能判斷一個字符串的類型是「str」還是「unicode」......除此之外,你明確地需要告訴它。 –

相關問題