2017-07-04 149 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