2015-02-24 51 views
1

我試圖修改http://www.java2s.com/Code/Java/Security/Basicsymmetricencryptionexample.htm的示例代碼,必須用3個參數,模式(加密或解密),IV和密鑰來調用。它還讀取和寫入特定文件。帶有彈性城堡的AES解密

截至目前,我無視給定的IV和密鑰,直到我將剩下的部分開始運行。我的代碼成功地從文件加密明文,並將密文寫入文件,但解密不起作用。看起來,解密模式讀取比加密寫更多的字節,我得到塊對齊錯誤。

我確定在解密部分的某處存在一些基本錯誤,但我不知道它是什麼。如果任何人都可以找出問題或可以看到任何可能導致它的明顯錯誤,請讓我知道。

該錯誤發生在

try{ ctLength += cipher.doFinal(cipherText, ctLength);}catch{IllegalBlockSizeException e) 

行代碼:

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.FileReader; 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.OutputStreamWriter; 
import java.io.PrintWriter; 
import java.io.Writer; 
import java.nio.charset.Charset; 
import java.nio.file.Files; 
import java.nio.file.Path; 
import java.nio.file.Paths; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import java.security.NoSuchProviderException; 
import java.security.Security; 
import java.util.Arrays; 
import javax.crypto.BadPaddingException; 
import javax.crypto.Cipher; 
import javax.crypto.IllegalBlockSizeException; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.ShortBufferException; 
import javax.crypto.spec.SecretKeySpec; 



@SuppressWarnings("unused") 
public class AESCTR { 
    static String inputFile = "plain-in.txt"; 
    static String outputFile = "cipher-out.txt"; 
    static String cInputFile = "cipher-in.txt"; 
    static String cOutputFile = "plain-out.txt"; 
    static String mode; 
    static String IV; 
    static String key; 
    public static void main(String[] args) { 
     if (Security.getProvider("BC") == null){ 
      System.out.println("Bouncy Castle provider is NOT available"); 
      System.exit(-1); 
     } 
     else{ 
      System.out.println("Bouncy Castle provider is available"); 
     } 
     Security.addProvider(Security.getProvider("BC")); 
     // TODO Auto-generated method stub 
     if (args.length != 3){ 
      System.out.println("Invalid number of arguments\n"); 
      System.exit(-1); 
     } 
     mode = args[0]; 
     IV = args[1]; 
     key = args[2]; 
     if ((!mode.equals("enc")) && (!mode.equals("dec"))){ 
      System.out.println("Invalid mode\n"); 
      System.exit(-1); 
     } 
     byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; 
     System.out.println(keyBytes.length); 
     SecretKeySpec key = new SecretKeySpec(keyBytes, "AES"); 
     System.out.println("Mode: " + mode + " IV: " + IV + " Key: " + key); 
     if(mode.equals("enc")){ 
      int ctLength = 0; 
      byte[] data = null; 
      try { 
       Path path = Paths.get(inputFile); 
       data = Files.readAllBytes(path); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
       System.out.println("Invalid Path\n"); 
       System.exit(-1); 
      } 
      while((data.length % 16) != 0){ //Padding 
       byte[] dest = new byte[data.length + 1]; 
       byte[] pad = new byte[] {0x00}; 
       System.arraycopy(data, 0, dest, 0, data.length); 
       System.arraycopy(pad, 0, dest, data.length, pad.length);  
       data = dest; 
      } 
      System.out.println(data.length); 
      byte[] cipherText = new byte[data.length]; 

      Cipher cipher = null; 
      try { 
       cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); 
      } catch (NoSuchAlgorithmException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (NoSuchProviderException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (NoSuchPaddingException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println("input text : " + new String(data)); 

      try { 
       cipher.init(Cipher.ENCRYPT_MODE, key); 
      } catch (InvalidKeyException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      try { 
       ctLength = cipher.update(data, 0, data.length, cipherText, 0);  
      } catch (ShortBufferException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      try { 
       ctLength += cipher.doFinal(cipherText, ctLength); 
      } catch (IllegalBlockSizeException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (ShortBufferException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (BadPaddingException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      Writer writer = null; 
      try{ writer = new BufferedWriter(new OutputStreamWriter(new  FileOutputStream(cInputFile), "utf-8")); 
      writer.write(new String(cipherText)); 
      } catch (IOException ex){ 
       System.out.println("File Write Error\n"); 
       System.exit(-1); 
      } finally{ 
       try{writer.close();}catch (Exception ex){} 
      } 

      byte[] c = null; 
      try { 
       Path path = Paths.get(cInputFile); 
       c = Files.readAllBytes(path); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
       System.out.println("Invalid Path\n"); 
       System.exit(-1); 
      } 
      System.out.println("cipher text: " + new String(c) + " bytes: " + ctLength); 
     } 
     else if (mode.equals("dec")){ 
      byte[] c = null; 
      try { 
       Path path = Paths.get(cInputFile); 
       c = Files.readAllBytes(path); 
       File f = new File(cInputFile); 
       System.out.println("In Bytes: " + c.length); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
       System.out.println("Invalid Path\n"); 
       System.exit(-1); 
      } 
      Cipher cipher = null; 
      try { 
       cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); 
      } catch (NoSuchAlgorithmException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } catch (NoSuchProviderException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } catch (NoSuchPaddingException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } 
      byte[] plainText = new byte[c.length]; 
      try { 
       cipher.init(Cipher.DECRYPT_MODE, key); 
      } catch (InvalidKeyException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      int ptLength = 0; 
      try { 
       ptLength = cipher.update(c, 0, c.length, plainText, 0); 
       System.out.println(ptLength); 
      } catch (ShortBufferException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      try { 
       ptLength += cipher.doFinal(plainText, ptLength); 
      } catch (IllegalBlockSizeException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (ShortBufferException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } catch (BadPaddingException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println("plain text : " + new String(plainText) + " bytes: " + ptLength); 
     } 
    } 
} 
+0

有什麼確切的例外,它在哪兒扔?請將這些信息添加到您的問題中。 – 2015-02-24 19:45:52

+0

錯誤發生在try {ctLength + = cipher.doFinal(cipherText,ctLength);} catch {IllegalBlockSizeException e)@Artjom B. – CSjunkie 2015-02-24 19:56:37

+2

該加密示例非常基本,因此它既不安全也不正確。在「示例」中已經存在將密文顯示爲字符串的錯誤。不要對互聯網上的隨機代碼樣本給予任何信任,特別是在涉及加密時。 – 2015-02-24 20:21:03

回答

2

您正在嘗試解碼大量的隨機字節爲UTF-8編碼的文本。這是行不通的。您的密碼文本會被破壞,因爲任何不構成字符的有效UTF-8編碼的字節序列將被替換字符0 + FFFD(�)替換。

密文實際上不是文本。不要使用與文本一起使用的WriterReader之類的API。使用與字節數組一起使用的API,如OutputStreamInputStream

如果您需要將密文保存爲文本,請使用Base64等二進制到文本編碼對其進行編碼。

具體來說,你應該像這樣更換您的密文的寫:

try { 
    Files.write(Paths.get(cInputFile), cipherText); 
} catch (IOException ex) { 
    System.out.println("File Write Error"); 
    System.exit(-1); 
} 
+2

感謝解決了這個問題,這個例子是由我的教授提供的,所以我不確定它爲什麼使用不正確的方法。註定從一開始haha @erickson – CSjunkie 2015-02-24 20:36:56

+0

@erickson在加密之前從純文本文件讀取UTF-8編碼是一個好主意嗎?並將解密後的文件寫爲UTF-8,或者應將它們視爲字節文件。 – CSjunkie 2015-02-24 20:56:38

+2

@CSjunkie這取決於編寫純文本文件時使用的編碼;他們應該匹配。如果您自己編寫文件,則很可能使用系統上的默認編碼。在linux上,'locale charmap'會告訴你。在Windows上,我認爲它是'chcp'。 – erickson 2015-02-24 21:00:53