2013-11-04 101 views
1

我想用Java解密AES加密的消息。我一直在嘗試standard libraryBouncyCastle的各種算法/模式/填充選項。沒有:-(在Java中解密AES編碼的消息(用Python加密)

加密實體是用Python編寫,並已在生產運氣加密郵件已經出去了,所以我不能輕易改變的那部分的Python代碼看起來是這樣的:

from Crypto.Cipher import AES 
import base64 
import os 
import sys 

BLOCK_SIZE = 16 
PADDING = '\f' 

pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING 

EncodeAES = lambda c, s: base64.b64encode(c.encrypt(pad(s))) 
DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING) 

secret = 'XXXXXXXXXXXXXXXX' 

cipher = AES.new(secret) 

clear='test' 
encoded = EncodeAES(cipher, clear) 

print 'Encrypted string:>>{}<<'.format(encoded) 

decoded = DecodeAES(cipher, encoded) 

print 'Decrypted string:>>{}<<'.format(decoded) 

顯然使用了AES,我發現我必須使用ECB模式,但是我還沒有找到適用於Java端的填充模式,如果輸入符合塊大小並且沒有填充,我可以解密如果消息需要填充,解密失敗

解密的Java代碼如下所示:

public class AESPaddingTest { 

    private enum Mode { 
     CBC, ECB, CFB, OFB, PCBC 
    }; 

    private enum Padding { 
     NoPadding, PKCS5Padding, PKCS7Padding, ISO10126d2Padding, X932Padding, ISO7816d4Padding, ZeroBytePadding 
    } 

    private static final String ALGORITHM = "AES"; 
    private static final byte[] keyValue = new byte[] { 'X', 'X', 'X', 'X', 
      'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X' }; 

    @BeforeClass 
    public static void configBouncy() { 
     Security.addProvider(new BouncyCastleProvider()); 
    } 

    @Test 
    public void testECBPKCS5Padding() throws Exception { 
     decrypt("bEpi03epVkSBTFaXlNiHhw==", Mode.ECB, 
       Padding.PKCS5Padding); 
    } 

    private String decrypt(String valueToDec, Mode modeOption, 
      Padding paddingOption) throws GeneralSecurityException { 
     Key key = new SecretKeySpec(keyValue, ALGORITHM); 

     Cipher c = Cipher.getInstance(ALGORITHM + "/" + modeOption.name() + "/" + paddingOption.name()); 

     c.init(Cipher.DECRYPT_MODE, key); 

     byte[] decValue = c.doFinal(valueToDec.getBytes()); 

     String clear = new String(Base64.encodeBase64(decValue)); 

     return clear; 
    } 

} 

引發的錯誤是:

javax.crypto.IllegalBlockSizeException:輸入長度必須多個16時 的帶襯墊的密

任何想法解密?

+0

如果您可以共享解密時收到的錯誤消息,那麼它會加快解決過程。 – lkamal

+0

當然可以。拋出'javax.crypto.IllegalBlockSizeException:當使用填充密碼解密時,輸入長度必須是16的倍數'異常。 –

+0

在將它傳遞給解密函數之前,您是首先解碼Base64編碼的消息嗎? – initramfs

回答

1

您正在使用換頁符填充(\f)。我不知道這樣做的標準填充方案。因此,我建議您在Java端選擇NoPadding,並準備從解密後得到的明文中去除\f個字符。

由於您可以解密未填充的明文,因此它表明您在雙方都有相同的密鑰材料(這是我很高興能夠從列表中刪除的一個常見問題)。

the Python documentation,它看起來像默認情況下選擇ECB模式。所以確保你在Java端使用它。

+0

你是對的,NoPadding。我的測試代碼的主要問題是encodeBase64的順序和解密。我剛剛意識到,當我嘗試了你的建議。正確的工作代碼: byte [] decodeBase64 = Base64.decodeBase64(valueToDec.getBytes()); Key key = new SecretKeySpec(keyValue,ALGORITHM); 密碼c =密碼。的getInstance( 「AES/ECB/NoPadding」); c.init(Cipher.DECRYPT_MODE,key); byte [] encValue = c.doFinal(decodeBase64); return new String(encValue).trim(); –

3

感謝您的好問題,答案和意見。 我對代碼做了小的修改,現在它對我來說就像是一種魅力。

import java.security.GeneralSecurityException; 
import java.security.Key; 
import java.security.Security; 

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 

import android.util.Base64; 

public class AESTest { 

    public enum Mode { 
     CBC, ECB, CFB, OFB, PCBC 
    }; 

    public enum Padding { 
     NoPadding, PKCS5Padding, PKCS7Padding, ISO10126d2Padding, X932Padding, ISO7816d4Padding, ZeroBytePadding 
    } 

    private static final String ALGORITHM = "AES"; 

    private static final byte[] keyValue ="myKey".getBytes(); 


    String decrypt(String valueToDec, Mode modeOption, 
      Padding paddingOption) throws GeneralSecurityException { 



     byte[] decodeBase64 = Base64.decode(valueToDec.getBytes(),0); 

     Key key = new SecretKeySpec(keyValue, ALGORITHM); 
     Cipher c = Cipher.getInstance("AES/ECB/NoPadding"); 
     c.init(Cipher.DECRYPT_MODE, key); 
     byte[] encValue = c.doFinal(decodeBase64); 
     return new String(encValue).trim(); 

    } 

} 

然後,我用的類我的Android活動如下:

AESTest aes=new AESTest(); 
String decrypted = aes.decrypt(myCipheredText,Mode.ECB,Padding.NoPadding); 

注意的是Python代碼的myKey祕密Java代碼是相同裏邊反。