2011-06-17 92 views
0

我有以下解密文件的代碼。爲什麼RC4無法處理大量的加密數據?

package encryption; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.security.Security; 

import javax.crypto.Cipher; 
import javax.crypto.CipherInputStream; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 

import org.bouncycastle.jce.provider.BouncyCastleProvider; 

public class Decrypter { 

    private static final String PASSWORD = "t_9Y#[email protected][h3}-7!"; 
    private static final String KEY_ALGORITHM = "PBEWithMD5AndDES"; 
    private static final String CIPHER_ALGORITHM = "RC4"; //Using Salsa20 or HC256 solves the problem 
    private static final String PROVIDER = "BC"; 

    public static void main(String[] args) throws Exception { 
     Security.addProvider(new BouncyCastleProvider()); 

     File inputFile = new File(args[0]); 
     File outputFile = new File(args[1]); 

     SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM); 
     SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD.toCharArray())); 

     Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 
     cipher.init(Cipher.DECRYPT_MODE, key); 

     InputStream inputStream = new FileInputStream(inputFile); 
     OutputStream outputStream = new FileOutputStream(outputFile); 

     CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher); 

     byte []byteBuffer = new byte[(int)inputFile.length()]; 
     cipherInputStream.read(byteBuffer); 
     outputStream.write(byteBuffer); //Only 512bytes of decrypted data is written to file, the rest becomes null 
     outputStream.close(); 
    } 

} 

我的問題是我做錯了什麼?爲什麼RC4不能解密超過512字節的數據塊?

回答

2

@邁克爾Lowman的具有正確的答案,但我想我會表現出另一種方式只是爲了做廣告DataInputStream類的功能。

通過使用DataInputStream.readFully()方法,您可以像「perl slurp」這樣的「全讀一遍」行爲。在您的示例中,您可以使用此方法讀取字節,然後將它們寫出來並使用CipherOutputStream而不是CipherInputStream進行解密。

考慮以下片段爲例:

byte[] byteBuffer = new byte[(int) inputFile.length()]; 
    DataInputStream dis = new DataInputStream(inputStream); 
    dis.readFully(byteBuffer); 
    dis.close(); 
    CipherOutputStream cos = new CipherOutputStream(outputStream, cipher); 
    cos.write(byteBuffer); 
    cos.close(); 
0

InputStream.read只返回一定數量的數據,你應該循環,直到流爲空。不過我建議你使用commons-io的org.apache.commons.io.FileUtils.copyInputStreamToFile(InputStream, File)複製流而不是滾動你自己的...

+0

我不認爲這是問題。您能否指出任何說明FileInputStream將讀取任意數量數據的Oracle文檔?這是一個阻塞流。即讀取方法調用將不會返回,直到所需的數據量被讀取,在這種情況下恰好是整個文件的大小。 – 2011-06-18 06:38:44

+1

@Monika Michael:javadocs不會這麼說。他們說該方法阻塞,直到有*數據可用。無論如何,你正在讀取CipherInputStream,而不是FileInputStream。 – 2011-06-18 14:58:53

+0

@GregS CipherInputStream鏈接到FileInputStream。 :-)阻塞直到數據變爲可用只有在通過網絡而不是從磁盤讀取數據時才成立。 – 2011-06-19 04:19:12

7

RC4是一個流密碼,所以它可以解碼任何數量的數據。您的問題是InputStreams不能以大塊讀取。通常情況下,您會循環讀取調用,直到沒有更多數據要讀取並使用小緩衝區。請參閱documentation of read()

這可以被實現爲

while(true) { 
    int numRead = cipherInputStream.read(byteBuffer); 
    if(numRead == -1) 
     break; 
    outputStream.write(byteBuffer, 0, numRead); 
}