2014-04-04 211 views
0

我有這個密碼學類。解密方法返回null

import java.security.*; 
import javax.crypto.*; 
import javax.crypto.spec.*; 
public class Crypto 
{ 
    public Crypto(){ 

    } 

    public static void main(String args[]){ 
     Crypto crypto = new Crypto(); 
     byte encrypted[] = crypto.encrypt("test encryption"); 
     System.out.println(encrypted); 
     String decrypted = crypto.decrypt(encrypted); 
     System.out.println(decrypted); 

    } 

    public byte[] encrypt(String input){ 
     try{ 
      Crypto crypto = new Crypto(); 
      SecretKeySpec key = crypto.hashPhrase(); 
      Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      aes.init(Cipher.ENCRYPT_MODE, key); 
      return aes.doFinal(input.getBytes()); 
     } 
     catch(Exception e){ 
      return null; 
     } 
    } 

    public SecretKeySpec hashPhrase(){ 
     try{ 
      String code = "some code"; 
      MessageDigest digest = MessageDigest.getInstance("SHA"); 
      digest.update(code.getBytes()); 
      return new SecretKeySpec(digest.digest(), 0, 16, "AES"); 
     } 
     catch(Exception e){ 
      return null; 
     } 
    } 

    public String decrypt(byte[] input){ 
     try{ 
      Crypto crypto = new Crypto(); 
      SecretKeySpec key = crypto.hashPhrase(); 
      Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      aes.init(Cipher.DECRYPT_MODE, key); 
      return new String(aes.doFinal(input)); 
     } 
     catch(Exception e){ 
      return null; 
     } 
    } 
} 

當我在這個類中運行main時,它工作正常。我看到一個加密值,然後在解密方法被調用後,我看到原始輸入 - 「測試加密」。

但是,當我嘗試實際使用解密方法時,遇到問題。我已經縮短了這個課程,只展示了相關的部分。

public void read() throws java.io.IOException{ 
    Crypto crypto = new Crypto(); 
    byte[] input; 
    BufferedReader in = new BufferedReader(new FileReader("C:\\Budget\\data.txt")); 
    while(in.ready()) { 
     input = in.readLine().getBytes(); 
     BudgetInterface.list.add(crypto.decrypt(input)); //ArrayList of Objects 
     System.out.println(crypto.decrypt(input)); 
     //BudgetInterface.list.add(in.readLine()); - artifact from version without cryptographic capability 
    } 
    in.close(); 
} 

BudgetInterface.list是對象的ArrayList,如前所述,並且我試圖輸入的解密版本添加到數組,但crypto.decrypt(輸入)返回在每一行文件。如果我刪除加密元素,它可以從文件中讀取沒有問題的行。如果我不嘗試解密,它也讀取得很好。爲什麼解密方法在此方法中返回null,但Crypto類的主要方法中沒有?

編輯:獲得堆棧跟蹤後,我得到的錯誤是javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher 我明白這是什麼話,但如何走到這一步,只有當我得到的東西從一個加密的文件,會發生什麼?我從文件中讀取的字節數組和我從Crypto中的主要方法獲得的字節數組長度相同。

+2

停止捕獲異常,吞下它們並返回'null',你可能會發現什麼地方出錯了。 *至少*將日誌記錄添加到您的catch塊中,理想情況下可以捕獲更具體的異常,並且最好不要捕獲它們,但讓它們冒泡到更高級別的代碼。哦,不要使用無參數的'String.getBytes()'或者'String(byte [])'構造函數 - 總是指定一個編碼。 –

+0

得到一個堆棧跟蹤,並添加了一個編輯到頂層的帖子,這並沒有多大幫助。文件中的字節數組和主函數生成的字節數組長度相同。 – Lighthat

+0

'FileReader'也使用默認的字符編碼,因爲你不能指定你自己的,所以它已經(或應該)半贊成包裝在'InputStreamReader'中的'FileInputStream'。 (FYI @JonSkeet) – ntoskrnl

回答

1
從一切

除此之外,最根本的你現在看到問題是,你要轉換二進制數據轉換爲僅使用平臺默認編碼的字符串,就好像它實際上只是文本一樣。這不是 - 它是二進制數據。

如果你想要每行加密輸入一行文本,這很好 - 但你需要將二進制數據轉換爲文本,如base64或類似的東西。永遠不會對任意二進制數據(加密數據,壓縮數據,圖像數據,音樂數據......基本上除了文本以外的任何東西)進行處理,就好像它只是編碼文本一樣。即使你確實有編碼文本,請明確指定編碼。

修復 - 並停止使用BufferedReader.ready(),寧願撥打readLine()並終止當它返回null - 你會處於更好的位置。當然,修復異常處理。

有關診斷此類事件的更多信息,請參閱我的blog post about reversible transformations,有關IO錯誤的更多信息,請參閱Marc Gravell's post about IO

+0

不使用BufferedReader.ready()的目的是什麼? – Lighthat

+1

@Lighthat:我懷疑你是在試圖用它來告訴你什麼時候有更多的數據需要閱讀,但這不是重點。它旨在告訴你什麼時候有更多數據可用*現在不阻塞*。我不記得上次我考慮這個或者'InputStream.available()'是一個很好的選擇。 –

0

看看你的解密方法是這樣做的:

catch(Exception e){ 
     return null; 
    } 

如果你不打算處理異常,你不應該抓住它。 或在非常至少,你應該打印堆棧跟蹤異常:

catch(Exception e){ 
     e.printStackTrace(); 
    }