2014-04-04 172 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(); 
    }