2013-04-23 40 views
7

Tôi đang phát triển một dự án bằng php nơi cần mã hóa các tệp được người dùng tải lên. Tệp này có thể từ 1mb đến 200mb nhiều hơn hoặc ít hơn. Tìm kiếm trên web, tôi đi đến kết luận rằng cách tốt nhất để làm điều đó là chia các tệp theo các phần, ví dụ, 4096 byte. Vì vậy, tôi mã hóa từng đoạn và nối nó vào tệp được mã hóa đầy đủ. Tôi đang thực sự sử dụng mã hóa và mã hóa AES-256 trong chế độ CBC. Vì vậy, câu hỏi của tôi là: 1) Tôi phải tạo một vector ban đầu mới cho mỗi đoạn, hoặc tôi có thể nhận được 16byte cuối cùng của khối cuối cùng của đoạn trước đó làm vector ban đầu của khối đầu tiên của đoạn hiện tại? Điều này sẽ dẫn đến chỉ có một iv để gắn thêm vào đầu của tập tin được mã hóa, và không phải là một iv cho mỗi đoạn để nối thêm trước đoạn mã hóa.Cách tiếp cận tốt nhất để mã hóa các tệp lớn bằng php

2) Để thêm xác thực HMAC. Câu hỏi này được liên kết với câu hỏi trước. Tôi có nên thêm nó cho toàn bộ tập tin hoặc cá nhân cho mỗi đoạn. Trong trường hợp này, làm cho nó cho toàn bộ tập tin là một vấn đề vì nó thường được thêm vào lúc bắt đầu của tập tin, và tôi không thể tính toán hmac cho đến khi tập tin được mã hóa hoàn tất.

3) Liên quan đến điều này. Để tải xuống tệp, bạn nên giải mã (theo khối) và gửi tệp cho người dùng cùng lúc hoặc tốt hơn là giải mã trước và gửi sau?

Cảm ơn

+1

Tại sao lại phát minh bánh xe? Tại sao không sử dụng một giải pháp đã tồn tại? –

+2

Nó sẽ là tuyệt vời nhưng tôi không thể tìm thấy một giải pháp cho việc này. Bạn có ý tưởng nào không? Cảm ơn! –

+0

Tại sao mã hóa theo khối? Bạn không cần phải cung cấp tệp đầy đủ trong một cuộc gọi để mã hóa nó dưới dạng một tệp. –

Trả lời

2

Tôi gặp phải vấn đề gần như giống nhau. Đây là giải pháp tôi phát hiện ra.

<?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); 
    } 
} 

?> 

Cách sử dụng:

<?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

Chế độ ECB? Rất nguy hiểm. Không ai nên sử dụng mã này như là. – mikeazo

+0

Đây là lý do tại sao bạn không muốn sử dụng chế độ ECB: http://crypto.stackexchange.com/a/20946/5299 (trong một số trường hợp, tệp có thể bị giải mã bởi thị lực !!) –

4

Bạn nên mã hóa các dòng tập tin và để cho PHP xử lý tất cả mọi thứ. Cụ thể là encryption filters kết hợp với stream_filter_append để làm những gì bạn muốn. Sau đó, bạn sẽ chỉ đọc các đoạn của tệp văn bản thô và ghi chúng vào luồng tệp đầu ra. Bộ lọc làm cho việc mã hóa xảy ra.

Bằng cách này bạn không sáng tạo lại bánh xe và đang sử dụng mã có khả năng đã được kiểm tra các vấn đề bảo mật.

Đối với hmac, hầu hết các thư viện cho phép bạn tiếp tục thêm dữ liệu vào hmac cho đến khi bạn gọi finalize hoặc một cái gì đó tương tự. Sau đó, bạn sẽ đọc trong các khối của bản mã, thêm chúng vào hmac. Lặp lại cho đến khi toàn bộ bản mã đã được thêm vào hmac và hoàn thành nó.

Hoặc, cài đặt openssl trên máy chủ và gọi hàm openssl từ bên trong PHP. Bạn có thể sử dụng chế độ mã hoá được xác thực, v.v.

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