2017-04-07 55 views
-1

美好的一天。我正在製作一個Java程序,它將讀取一個加密文件,並在密鑰的幫助下解密它。我使用這個AES Encryption算法,因爲它提供了我也需要的代碼。Java AES解密 - 給定最終塊未正確填充錯誤

我所做的是將Java Class複製到我的項目中。這就是我的AES.java文件看起來像:

public class AES{ 
    private static SecretKeySpec secretKey ; 
    private static byte[] key ; 

    private static String decryptedString; 
    private static String encryptedString; 


    public static void setKey(String myKey){ 


     MessageDigest sha = null; 
     try { 
      key = myKey.getBytes("UTF-8"); 
      System.out.println(key.length); 
      sha = MessageDigest.getInstance("SHA-1"); 
      key = sha.digest(key); 
      key = Arrays.copyOf(key, 16); // use only first 128 bit 
      System.out.println(key.length); 
      System.out.println(new String(key,"UTF-8")); 
      secretKey = new SecretKeySpec(key, "AES"); 


     } catch (NoSuchAlgorithmException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } catch (UnsupportedEncodingException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 




    } 

    public static String getDecryptedString() { 
     return decryptedString; 
    } 

    public static void setDecryptedString(String decryptedString) { 
     AES.decryptedString = decryptedString; 
    } 

    public static String getEncryptedString() { 
     return encryptedString; 
    } 

    public static void setEncryptedString(String encryptedString) { 
     AES.encryptedString = encryptedString; 
    } 

    public static String encrypt(String strToEncrypt){ 
     try{ 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 

      cipher.init(Cipher.ENCRYPT_MODE, secretKey); 

      setEncryptedString(Base64.encodeBase64String(cipher.doFinal(strToEncrypt.getBytes("UTF-8")))); 
      //    byte[] encodedBytes = Base64.getEncoder().encode(strToEncrypt.getBytes("UTF-8")); 
      //    setEncryptedString(new String(encodedBytes)); 

     } 
     catch (Exception e) 
     { 

      System.out.println("Error while encrypting: "+e.toString()); 
     } 
     return null; 

    } 

    public static String decrypt(String strToDecrypt){ 
     try{ 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING"); 

      cipher.init(Cipher.DECRYPT_MODE, secretKey); 
      setDecryptedString(new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt)))); 
      //setDecryptedString(new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)))); 


     } 
     catch (Exception e){ 

      System.out.println("Error while decrypting: "+e.toString()); 

     } 
     return null; 
    } 


    public static void main(String args[]){ 

     final String strToEncrypt = "My text to encrypt"; 
     final String strPssword = "encryptor key"; 
     AES.setKey(strPssword); 

     AES.encrypt(strToEncrypt.trim()); 

     System.out.println("String to Encrypt: " + strToEncrypt); 
     System.out.println("Encrypted: " + AES.getEncryptedString()); 

     final String strToDecrypt = AES.getEncryptedString(); 
     AES.decrypt(strToDecrypt.trim()); 

     System.out.println("String To Decrypt : " + strToDecrypt); 
     System.out.println("Decrypted : " + AES.getDecryptedString()); 
    } 
} 

在我Main.java類:我有以下幾點:我的文件

//I get my encoded input as a FileInputStream 
InputStream encodedInput = null; 
encodedInput = new FileInputStream("./Config/config2.properties"); 

//get the input and then convert to Bytes then to String 
//I also tried converting to String right away 
byte[] inputBytes = IOUtils.toByteArray(encodedInput); 
String theString = IOUtils.toString(inputBytes, "UTF-8"); //IOUtils.toString(encodedInput, "UTF-8"); 
System.out.println("Input string (encoded) = " + theString); 

//It stops at the decrypt call and throw the exception 
AES.setKey(localProperties.getKey()); 
AES.decrypt(theString.trim()); 
String decrypted = AES.getDecryptedString(); 

正如你所看到的,得到的內容。內容是正確的,因爲我也在系統日誌中打印它們。

但我不明白爲什麼解密函數不能解密它,即使函數要求輸入一個字符串。

我真的傻眼了,我不知道從哪裏開始。任何幫助將非常感激。

+1

嗯。你的PKCS5PADDING在解密和大寫情況下都是在加密中。我不確定這是否會導致問題,但值得堅持使用PKCS5Padding – slipperyseal

+0

**切勿使用[ECB模式](http://crypto.stackexchange.com/q/14487/13022)**。它是確定性的,因此不具有語義安全性。您至少應該使用[CBC](http://crypto.stackexchange.com/q/22260/13022)或[CTR](http://crypto.stackexchange.com/a/2378/)這樣的隨機模式。 13022)。最好是對密文進行身份驗證,以便像[padding oracle attack](http://crypto.stackexchange.com/q/18185/13022)這樣的攻擊是不可能的。這可以通過驗證模式(如GCM或EAX)或[加密 - 然後MAC](http://crypto.stackexchange.com/q/202/13022)方案完成。 –

+0

如果你的解密有問題,你應該顯示加密。儘管EJP的答案可能有幫助,但我不明白他的答案能夠解決您的問題。 –

回答

2
public static String decrypt(String strToDecrypt){ 

問題就在這裏。該方法應接受byte[]參數。您已將密文作爲byte[]陣列。你毫無意義的將它轉換爲String,只能將其轉換回此方法。往返不是無損的。只需將它作爲byte[]陣列傳遞即可。

String不是二進制數據的容器。

+0

好的。我用'byte []'而不是'String'取代了參數。用這個:'cipher.doFinal(byteToDecrypt)'代替。但是現在,我得到了一個輸入長度必須是16的倍數,當使用填充密碼解密時出錯。但是我輸入了344個字符長度,它是由divisble 16 – Razgriz

+0

我做了一個新的問題,而不是http://stackoverflow.com/questions/43268843/java-aes-file-decryption-input-length-not-multiple- of-16-bytes-when-padd – Razgriz

+0

爲什麼回答一個不可回答的問題? –

相關問題