2017-07-04 109 views
0

我想加密Java中的數據文件,然後在Python中解密。AES/CBC/PKCS5Padding加密在Java解密在Python中出錯

但解密的數據文件始終得到remainslike這

my normal content^@^@^@^@^@ 

一些填充字節其實我在Python代碼UNPAD行動(FUNC decrypt_file())

,當我刪除UNPAD行動,我得到這個:

my normal content^@^@^@^@^@^P^P^P^P^P^P^P^P^P^P^P^P^P^P^P^P 

如此,它似乎在Java加密方法做填充兩次。

我很困惑,卡在這裏。任何人都可以幫忙嗎?非常感謝!

這是我的代碼。

(1)Java版本

import java.io.File; 
import javax.crypto.Cipher; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 

public class AESUtil { 
    private static final String key = "wesurexZ5!Hcurfit"; 
    private static final String ivs = "zK2hzBvP%FRJ5%lD"; 
    public static byte[] encrypt(byte[] strInBytes) throws Exception { 
     SecretKeySpec skeySpec = getKey(key); 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     IvParameterSpec iv = new IvParameterSpec(ivs.getBytes("UTF-8")); 
     cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); 
     return cipher.doFinal(strInBytes); 
    } 

    public static byte[] decrypt(byte[] strIn) throws Exception { 
     SecretKeySpec skeySpec = getKey(key); 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     IvParameterSpec iv = new IvParameterSpec(ivs.getBytes("UTF-8")); 
     cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); 
     byte[] decrypted = cipher.doFinal(strIn); 
     return decrypted; 
    } 

    private static SecretKeySpec getKey(String strKey) throws Exception { 
     byte[] arrBTmp = strKey.getBytes(); 
     byte[] arrB = new byte[16]; 
     for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) { 
      arrB[i] = arrBTmp[i]; 
     } 
     SecretKeySpec skeySpec = new SecretKeySpec(arrB, "AES"); 
     return skeySpec; 
    } 
} 

(2)Python版本

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 

import sys 

reload(sys) 
sys.setdefaultencoding("utf-8") 

from Crypto.Cipher import AES 


class AESTool(object): 

    def __init__(self, iv, key): 
     self.iv = iv.decode("utf8") 
     self.key = key 
     bs = AES.block_size 
     self.pad = lambda s: s + (bs - len(s) % bs) * chr(bs - len(s) % bs) 
     self.unpad = lambda s: s[0:-ord(s[-1])] 

    def encrypt(self, plain_text): 
     try: 
      encryptor = AES.new(self.key, AES.MODE_CBC, self.iv) 
      encrypted_text = encryptor.encrypt(self.pad(plain_text)) 
     except Exception as ex: 
      raise Exception(ex.message) 

     return encrypted_text 

    def decrypt(self, decrypted_text): 
     try: 
      decryptor = AES.new(self.key, AES.MODE_CBC, self.iv) 
      plain_text = decryptor.decrypt(decrypted_text) 
     except Exception as ex: 
      raise Exception(ex.message) 

     return self.unpad(plain_text) 

    def encrypt_file(self, from_full_path, to_full_path, chunksize=64*1024): 
     encryptor = AES.new(self.key, AES.MODE_CBC, self.iv) 
     try: 
      with open(from_full_path, 'rb') as infile: 
       with open(to_full_path, 'wb') as outfile: 
        while True: 
         chunk = infile.read(chunksize) 

         if len(chunk) == 0: 
          break 

         if len(chunk) < chunksize: 
          outfile.write(encryptor.encrypt(self.pad(chunk))) 
          break 

         outfile.write(encryptor.encrypt(chunk)) 
     except Exception as ex: 
      return -1 

     return 0 

    def decrypt_file(self, from_full_path, to_full_path, chunksize=64*1024): 
     decryptor = AES.new(self.key, AES.MODE_CBC, self.iv) 
     try: 
      with open(from_full_path, 'rb') as infile: 
       with open(to_full_path, 'wb') as outfile: 
        prev_chunk = None 
        while True: 
         chunk = infile.read(chunksize) 

         if len(chunk) == 0 and prev_chunk: 
          outfile.write(self.unpad(decryptor.decrypt(prev_chunk))) 
          break 

         if prev_chunk: 
          outfile.write(decryptor.decrypt(prev_chunk)) 

         if len(chunk) < chunksize: 
          outfile.write(self.unpad(decryptor.decrypt(chunk))) 
          break 

         prev_chunk = chunk 
     except Exception as ex: 
      return -1 

     return 0 
+1

對於每種加密,IV需要隨機且不同。 – zaph

+0

@zaph我只知道重用固定的IV可能會導致安全問題。但是,這怎麼會帶來這樣的功能性問題呢?我不太明白,請問你能填補我嗎?非常感謝你。 – RonnieTsang

+0

該評論不僅針對OP,還針對未來的讀者,指出問題中的固定IV是安全性差。 – zaph

回答

-1

你知道,如果發生這種情況時,你只是使用默認模式嘗試和ENC/DEC?很想知道,因爲如果是這種情況,那麼我們有同樣的問題。我的意思是默認使用:

Cipher cipher = Cipher.getInstance("AES"); 

而不是;

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
+0

感謝您的信息。我不知道以前的默認模式可能會提取相同的問題。但是,當然,加密/解密aross不同的平臺可能會導致填充相關問題的不確定性。我正在尋找跨平臺的方式來使用aes,並且我找到了[aes-cross](https://github.com/keel/aes-cross)。作者的結論是「如果您在平臺上找到了AES/CBC/PKCS5Padding的方法,那麼您已經獲得了跨平臺的AES解決方案。」所以我的代碼在 – RonnieTsang

+0

以上總是最好完全指定加密屬性,如模式和填充。 – zaph