2013-04-23 10 views
7

Sto sviluppando un progetto in php in cui è necessario crittografare i file caricati dagli utenti. Questi file potrebbero essere da 1mb a 200mb più o meno. Cercando sul web, sono giunto alla conclusione che il modo migliore per farlo era dividere i file in blocchi di, ad esempio, 4096 byte. Quindi crittaggio ogni pezzo e lo aggiungo al file crittografato completo. In realtà sto usando la crittografia mcrypt e AES-256 in modalità CBC.Miglior approccio per crittografare i file di grandi dimensioni con php

Quindi, le mie domande sono: 1) devo creare un nuovo vettore iniziale per ogni pezzo, o posso ottenere gli ultimi 16bytes dell'ultimo blocco di un pezzo precedente come vettore iniziale del primo blocco del pezzo attuale? Ciò si tradurrà nell'avere un iv iv da aggiungere all'inizio del file crittografato, e non un iv per ogni chunk da aggiungere prima del chunk encrpyted.

2) Per aggiungere un'autenticazione HMAC. Questa domanda è collegata alla precedente. Dovrei aggiungerlo per l'intero file o singolarmente per ogni blocco. In questo caso, eseguirlo per l'intero file è un problema poiché viene solitamente aggiunto all'inizio del file e non è possibile calcolare l'hmac fino a quando il file crittografato non è completo.

3) Relativo a questo. Per il download dei file, è consigliabile decodificare (in blocchi) e inviare file all'utente contemporaneamente o è meglio decifrare prima e inviare successivamente?

Grazie

+1

Perché reinventare la ruota? Perché non utilizzare una soluzione già esistente? –

+2

Sarebbe bello ma non riesco a trovare una soluzione per questo. Ne hai idea? Grazie! –

+0

Perché crittografare in blocchi? Non è necessario fornire il file completo in una chiamata per crittografarlo come un unico file. –

risposta

2

Ho avuto problemi quasi identici. Ecco la soluzione che ho scoperto.

<?php 

$filecrypt = new filecrypt(); 

class filecrypt{ 

    var $_CHUNK_SIZE; 

    function __construct(){ 
     $this->_CHUNK_SIZE = 100*1024; // 100Kb 
    } 

    public function encrypt($string, $key){ 
     $key = pack('H*', $key); 
     if (extension_loaded('mcrypt') === true) return mcrypt_encrypt(MCRYPT_BLOWFISH, substr($key, 0, mcrypt_get_key_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB)), $string, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND)); 
     return false; 
    } 

    public function decrypt($string, $key){ 
     $key = pack('H*', $key); 
     if (extension_loaded('mcrypt') === true) return mcrypt_decrypt(MCRYPT_BLOWFISH, substr($key, 0, mcrypt_get_key_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB)), $string, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB), MCRYPT_RAND)); 
     return false; 
    } 

    public function encryptFileChunks($source, $destination, $key){ 
     return $this->cryptFileChunks($source, $destination, $key, 'encrypt'); 
    } 

    public function decryptFileChunks($source, $destination, $key){ 
     return $this->cryptFileChunks($source, $destination, $key, 'decrypt'); 
    } 

    private function cryptFileChunks($source, $destination, $key, $op){ 

     if($op != "encrypt" and $op != "decrypt") return false; 

     $buffer = ''; 
     $inHandle = fopen($source, 'rb'); 
     $outHandle = fopen($destination, 'wb+'); 

     if ($inHandle === false) return false; 
     if ($outHandle === false) return false; 

     while(!feof($inHandle)){ 
      $buffer = fread($inHandle, $this->_CHUNK_SIZE); 
      if($op == "encrypt") $buffer = $this->encrypt($buffer, $key); 
      elseif($op == "decrypt") $buffer = $this->decrypt($buffer, $key); 
      fwrite($outHandle, $buffer); 
     } 
     fclose($inHandle); 
     fclose($outHandle); 
     return true; 
    } 

    public function printFileChunks($source, $key){ 

     $buffer = ''; 
     $inHandle = fopen($source, 'rb'); 

     if ($inHandle === false) return false; 

     while(!feof($inHandle)){ 
      $buffer = fread($inHandle, $this->_CHUNK_SIZE); 
      $buffer = $this->decrypt($buffer, $key); 
      echo $buffer; 
     } 
     return fclose($inHandle); 
    } 
} 

?> 

Usage:

<?php 
    $key = '3da541559918a808c2402bba5012f6c60b27661c'; // Your encryption key 
    $filecrypt->encryptFileChunks('I-still-loooove-hula-hoop.gif', 'encrypted.gif', $key); 
    $filecrypt->decryptFileChunks('encrypted.gif', 'decrypted.gif', $key); 
?> 
+1

Modalità ECB? Molto pericoloso. Nessuno dovrebbe usare questo codice così com'è. – mikeazo

+0

Ecco il motivo per cui non si desidera utilizzare la modalità ECB: http://crypto.stackexchange.com/a/20946/5299 (in alcuni casi, il file può essere decodificato da vista !!) –

4

Si dovrebbe crittografare il flusso di file e lasciare PHP gestire tutto. In particolare encryption filters combinato con stream_filter_append per fare quello che vuoi. Quindi si dovrebbero leggere blocchi del file di testo in chiaro e scriverli nello stream del file di output. Il filtro provoca la crittografia.

In questo modo non si reinventa la ruota e si sta utilizzando il codice che è stato probabilmente verificato per problemi di sicurezza.

Per hmac, la maggior parte delle librerie consente di continuare ad aggiungere dati all'hmac finché non si chiama finalize o qualcosa del genere. Quindi leggi i blocchi di testo cifrato, aggiungili all'hmac. Ripeti fino a quando l'intero testo cipher è stato aggiunto a hmac e finalizzato.

Oppure installa openssl sul server e chiama le funzioni openssl da PHP. È possibile utilizzare una modalità di crittografia autenticata, ecc.

Problemi correlati