2014-12-27 49 views
4

我有以下一段Java代碼,我想用Python進行復制。Python的AES解密

public class AESDecryption { 

    protected SecretKeySpec getPublicKey() { 

     try { 
      byte[] key = "MuidKeibimbtjph9".getBytes("UTF-8"); 
      key = MessageDigest.getInstance("SHA-256").digest(key); 
      key = Arrays.copyOf(key, 32); 
      return new SecretKeySpec(key, "AES"); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (UnsupportedEncodingException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    public String decrypt(byte[] data) { 
     Cipher cipher = null; 
     try { 
      cipher = Cipher.getInstance("AES/CBC/NoPadding"); 
      cipher.init(2, new SecretKeySpec(getPublicKey().getEncoded(), "AES"), new IvParameterSpec(new byte[cipher.getBlockSize()])); 
      byte decryptedBytes[] = cipher.doFinal(data); 
      return new String(Arrays.copyOf(decryptedBytes, decryptedBytes.length - decryptedBytes[-1 + decryptedBytes.length])); 
     } catch (NoSuchAlgorithmException e) { 
      e.printStackTrace(); 
     } catch (NoSuchPaddingException e) { 
      e.printStackTrace(); 
     } catch (IllegalBlockSizeException e) { 
      e.printStackTrace(); 
     } catch (BadPaddingException e) { 
      e.printStackTrace(); 
     } catch (InvalidAlgorithmParameterException e) { 
      e.printStackTrace(); 
     } catch (InvalidKeyException e) { 
      e.printStackTrace(); 
     } 
     return ""; 
    } 

    public static void main(String[] args) { 
     try { 
      byte[] content = Files.readAllBytes(Paths.get("/tmp/dump.gzip")); 
      AESDecryption aesDecryption = new AESDecryption(); 
      System.out.println(aesDecryption.decrypt(content)); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

此代碼來自客戶端應用程序。我在生成加密內容的服務器端沒有權力。對於這個問題,我已經改變了對稱密鑰以及如何檢索內容(在這個例子中是從一個文件,但實際上來自https響應)

我想使用PyCrypto庫在python腳本中複製此功能。這就是我的初始代碼的樣子:

from Crypto.Cipher import AES 
from Crypto.Hash import SHA256 
from Crypto import Random 

BLOCK_SIZE = 16 
unpad = lambda s: s[0:-ord(s[-1])] 

hash = SHA256.new() 
hash.update('MuidKeibimbtjph9') 
symmetric_key = hash.digest() 
symmetric_key = symmetric_key[:32] 

bytes_store = None 
with open('/tmp/dump.gzip','r') as f: 
    bytes_store = f.read() 

rndfile = Random.new() 
aes_decryptor = AES.new(symmetric_key, AES.MODE_CBC, rndfile.read(BLOCK_SIZE)) 
print unpad(aes_decryptor.decrypt(bytes_store)) 

在加密文件上運行java代碼就行得通。結果看起來像這樣:

{"code":200,"status":"ok","api_version":"0.0.0","data":[.....],"notifications":{}} 

但是,python複製轉儲「半解密」文本。那種..

=c�q[A�$�dl�tus":"ok","api_version":"0.0.0","data":[.....],"notifications":{}} 

我不能做任何事情。看看Java代碼,清楚的是cipter塊中沒有填充,所以我認爲服務器端的數據可能已經是密碼塊大小的倍數。還有很多▯▯▯ python輸出結尾的字符,但我很快通過解密數據解除了它們。儘管如此,我還是無法弄清楚我的做法是錯誤的,即有效載荷的第一部分是混亂的。 我對數據加密的知識是非常基本的,因此我正在向您尋求知識:)

回答

4

問題是,服務器代碼使用固定的IV(這是壞的)與零,但在您的蟒蛇代碼,你將一個新的隨機生成的IV傳遞給AES.new

您可以用"\x00"*BLOCK_SIZE替換rndfile.read(BLOCK_SIZE)

+0

我同意Python代碼使用隨機IV,而Java代碼似乎不是,但如果這是問題,「半解密」文本是不是完全亂碼? – unutbu 2014-12-27 19:08:04

+4

@unutbu:在CBC模式下,只有第一個塊在解密方向*上受到影響*。 P_n = D(C_n)xor C_n-1。 – 2014-12-27 19:10:37

+1

太棒了,謝謝。現在在仔細閱讀維基百科有關CBC模式的文章之後 - 它確實說明IV對於CBC必須是正確的,否則第一塊明文將會損壞,但後續的明文塊將是正確的。 – 2014-12-27 19:23:05