2012-09-28 29 views
9

Tôi đang sử dụng CipherInputStream và CipherOutputStream để mã hóa các tệp bằng AES.CipherInputStream chỉ đọc 16 byte (AES/Java)

encrypt(...) có vẻ hoạt động tốt, nhưng hàm decrypt(...) của tôi chỉ giải mã 16 byte đầu tiên của tệp của tôi.

Đây là lớp học của tôi:

public class AESFiles { 

    private byte[] getKeyBytes(final byte[] key) throws Exception { 
     byte[] keyBytes = new byte[16]; 
     System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length)); 
     return keyBytes; 
    } 

    public Cipher getCipherEncrypt(final byte[] key) throws Exception { 
     byte[] keyBytes = getKeyBytes(key); 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); 
     IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); 
     return cipher; 
    } 

    public Cipher getCipherDecrypt(byte[] key) throws Exception { 
     byte[] keyBytes = getKeyBytes(key); 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); 
     IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes); 
     cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); 
     return cipher; 
    } 

    public void encrypt(File inputFile, File outputFile, byte[] key) throws Exception { 
     Cipher cipher = getCipherEncrypt(key); 
     FileOutputStream fos = null; 
     CipherOutputStream cos = null; 
     FileInputStream fis = null; 
     try { 
      fis = new FileInputStream(inputFile); 
      fos = new FileOutputStream(outputFile); 
      cos = new CipherOutputStream(fos, cipher); 
      byte[] data = new byte[1024]; 
      int read = fis.read(data); 
      while (read != -1) { 
       cos.write(data, 0, read); 
       read = fis.read(data); 
       System.out.println(new String(data, "UTF-8").trim()); 
      } 
      cos.flush(); 
     } finally { 
      fos.close(); 
      cos.close(); 
      fis.close(); 
     } 
    } 

    public void decrypt(File inputFile, File outputFile, byte[] key) throws Exception { 
     Cipher cipher = getCipherDecrypt(key); 
     FileOutputStream fos = null; 
     CipherInputStream cis = null; 
     FileInputStream fis = null; 
     try { 
      fis = new FileInputStream(inputFile); 
      cis = new CipherInputStream(fis, cipher); 
      fos = new FileOutputStream(outputFile); 
      byte[] data = new byte[1024]; 
      int read = cis.read(data); 
      while (read != -1) { 
       fos.write(data, 0, read); 
       read = cis.read(data); 
       System.out.println(new String(data, "UTF-8").trim()); 
      } 
     } finally { 
      fos.close(); 
      cis.close(); 
      fis.close(); 
     } 
    } 

    public static void main(String args[]) throws Exception { 
     byte[] key = "mykey".getBytes("UTF-8"); 
     new AESFiles().encrypt(new File("C:\\Tests\\secure.txt"), new File("C:\\Tests\\secure.txt.aes"), key); 
     new AESFiles().decrypt(new File("C:\\Tests\\secure.txt.aes"), new File("C:\\Tests\\secure.txt.1"), key); 
    } 
} 

Vì vậy, câu hỏi của tôi là, tại sao các decrypt chức năng chỉ đọc 16 byte đầu tiên?

+0

Làm thế nào để bạn biết nó giải mã chỉ 16 byte? Bạn có thể chỉnh sửa bài đăng của mình để hiển thị ngoại lệ bạn đang nhận được không? – Gray

+0

Tôi không nhận được bất kỳ ngoại lệ nào. Kích thước của tệp "secure.txt.1" (tệp được giải mã) chỉ có 16 byte, trong khi nguồn có 41 byte. – Joshua

+0

Lưu ý rằng việc sử dụng 'CipherInputStream' rất phức tạp vì nó quét các ngoại lệ dưới thảm (đó là một câu tục ngữ có nghĩa là nó ẩn chúng). Tôi sẽ không tự mình sử dụng nó. –

Trả lời

12

Điều này rất tinh tế. Vấn đề của bạn là bạn đang đóng fostrướccos của mình. Trong phương pháp encrypt(...) của bạn, bạn đang làm:

} finally { 
    fos.close(); 
    cos.close(); 
    fis.close(); 
} 

Đó đóng FileOutputStream ra từ dưới CipherOutputStream nên khối đệm cuối cùng của sản lượng được mã hóa không bao giờ được ghi vào tập tin đầu ra. Nếu bạn đóng fossau số cos thì mã của bạn sẽ hoạt động tốt.

Thực sự, bạn nên xem xét làm một cái gì đó như:

FileOutputStream fos = null; 
    CipherOutputStream cos = null; 
    FileInputStream fis = null; 
    try { 
     fis = new FileInputStream(inputFile); 
     fos = new FileOutputStream(outputFile); 
     cos = new CipherOutputStream(fos, cipher); 
     // once cos wraps the fos, you should set it to null 
     fos = null; 
     ... 
    } finally { 
     if (cos != null) { 
      cos.close(); 
     } 
     if (fos != null) { 
      fos.close(); 
     } 
     if (fis != null) { 
      fis.close(); 
     } 
    } 

FYI: org.apache.commons.io.IOUtilscloseQuietly(...) phương pháp tuyệt vời mà xử lý null kiểm tra và bắt các ngoại lệ cho bạn.

+0

Wow! Cảm ơn bạn rât nhiêu!!! – Joshua

+0

giải pháp rất đẹp .. –

+1

Bây giờ điều này có thể được xử lý bằng cách sử dụng try-with-resources. Lưu ý rằng bạn có thể chỉ định nhiều luồng trong câu lệnh 'try', sẽ được tự động đóng và - tất nhiên - theo thứ tự đúng (ngược lại). –

Các vấn đề liên quan