2015-12-24 16 views
5

Ho testato il mio codice con file inferiori a questo (10mb, 100mb, 500mb) e la crittografia funziona. Tuttavia, eseguo problemi con file superiori a 1 GB. Ho generato un file di grandi dimensioni (circa 2GB) e voglio cifrare con AES utilizzando Java, ma sto correndo in questo errore:Crittografia di un file di grandi dimensioni con AES utilizzando JAVA

"Exception in thread 'main' java.lang.OutOfMemoryError: Java heap space "

Ho provato ad aumentare la memoria disponibile usando -Xmx8G, ma senza dadi. Parte del mio codice è il seguente

File selectedFile = new File("Z:\\dummy.txt");   
    Path path = Paths.get(selectedFile.getAbsolutePath());  
    byte[] toencrypt = Files.readAllBytes(path);  
    byte[] ciphertext = aesCipherForEncryption.doFinal(toencrypt); 
    FileOutputStream fos = new FileOutputStream(selectedFile.getAbsolutePath()); 
    fos.write(ciphertext); 
    fos.close(); 

Per quanto posso dire, la ragione per cui si comporta in questo modo, è che si sta cercando di leggere l'intero file in una sola volta, cifrare, e memorizzarlo nella un altro array di byte invece di eseguire il buffering e lo streaming. Qualcuno può aiutarmi con alcuni suggerimenti sul codice?

Sono un principiante della programmazione, quindi non so molto, qualsiasi aiuto sarà apprezzato.

risposta

10

Non provare nemmeno a leggere interi file di grandi dimensioni in memoria. Cripta un buffer alla volta. Basta fare il ciclo di copia standard con uno CipherOutputStream opportunamente inizializzato attorno allo FileOutputStream. Puoi usarlo per tutti i file, non è necessario creare un caso speciale. Utilizzare un buffer di 8k o più.

EDIT Il 'ciclo copia standard' in Java è la seguente:

byte[] buffer = new byte[8192]; 
int count; 
while ((count = in.read(buffer)) > 0) 
{ 
    out.write(buffer, 0, count); 
} 

dove in questo caso out = new CipherOutputStream(new FileOutputStream(selectedFile), cipher).

+1

"crittografia di un byte alla volta": Con la crittografia cifrari a blocchi è dal blocco (AES: 16-byte). – zaph

+0

Dopo aver letto la risposta di EJP, sono ancora incerto su cosa si intende per "ciclo di copia standard". Capisco che ho bisogno di leggere l'input un byte alla volta o in blocchi. Non sono sicuro di cosa fare con il ciclo. Qualcuno può indicarmi una direzione per iniziare la mia ricerca? Per quanto riguarda la parte di flusso di uscita cifra di esso, dovrebbe essere simile a questo: CipherOutputStream cos = new CipherOutputStream (FileOutputStream (selectedFile.getAbsolutePath()); – halcyondayz

+0

@zaph Ops, che è stato un errore di battitura per 'tampone', ma "Cipher' si prende cura delle dimensioni del blocco sottostante per te. – EJP

1

È inoltre possibile semplificare ulteriormente il processo utilizzando Encryptor4j: https://github.com/martinwithaar/Encryptor4j

File srcFile = new File("original.zip"); 
File destFile = new File("original.zip.encrypted"); 
String password = "mysupersecretpassword"; 
FileEncryptor fe = new FileEncryptor(password); 
fe.encrypt(srcFile, destFile); 

Questa libreria utilizza lo streaming di crittografia in modo da non causare OutOfMemoryError anche con file di grandi dimensioni. Inoltre, invece di usare le password puoi usare anche il tuo Key.

Partenza l'esempio nella pagina Github qui: https://github.com/martinwithaar/Encryptor4j#file-encryption