7

ユーザーがアップロードしたファイルを暗号化する必要があるプロジェクトをphpで開発しています。このファイルは、1 mb から 200 mb の範囲で多かれ少なかれ可能性があります。Web で検索した結果、ファイルを 4096 バイトのチャンクに分割するのが最善の方法であるという結論に達しました。そのため、すべてのチャンクを暗号化し、完全な暗号化ファイルに追加します。私は実際に CBC モードで mcrypt と AES-256 暗号化を使用しています。

したがって、私の質問は次のとおりです。1) チャンクごとに新しい初期ベクトルを作成する必要がありますか、それとも前のチャンクの最後のブロックの最後の 16 バイトを現在のチャンクの最初のブロックの初期ベクトルとして取得できますか? これにより、暗号化されたファイルの先頭に追加する iv が 1 つだけになり、暗号化されたチャンクの前に追加するチャンクごとに iv が 1 つではなくなります。

2) HMAC 認証を追加するため。この質問は前の質問にリンクされています。ファイル全体に追加するか、チャンクごとに個別に追加する必要があります。この場合、通常はファイルの先頭に追加されるため、ファイル全体に対して行うのは問題であり、暗号化されたファイルが完成するまで hmac を計算できません。

3) これに関連する。ファイルのダウンロードの場合、(チャンクで) 復号化してファイルを同時にユーザーに送信するのは良い考えですか、それとも最初に復号化して後で送信する方が良いですか?

ありがとう

4

2 に答える 2

5

ファイル ストリームを暗号化し、PHP にすべてを処理させる必要があります。特に、暗号化フィルターをstream_filter_appendと組み合わせて、必要なことを行います。次に、プレーンテキスト ファイルのチャンクを読み取り、それらを出力ファイル ストリームに書き込みます。フィルタにより、暗号化が行われます。

この方法では、一からやり直す必要はなく、セキュリティ問題について監査済みの可能性が高いコードを使用しています。

hmac の場合、ほとんどのライブラリでは、finalize などを呼び出すまで hmac にデータを追加し続けることができます。次に、暗号文のチャンクを読み取り、それらを hmac に追加します。暗号文全体が hmac に追加されるまで繰り返し、最終化します。

または、サーバーに openssl をインストールし、PHP 内から openssl 関数を呼び出します。認証された暗号モードなどを使用できます。

于 2014-04-21T18:33:42.050 に答える
0

私はほとんど同じ問題を抱えていました。これが私が見つけた解決策です。

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

?>

使用法:

<?php
    $key = '3da541559918a808c2402bba5012f6c60b27661c'; // Your encryption key
    $filecrypt->encryptFileChunks('I-still-loooove-hula-hoop.gif', 'encrypted.gif', $key);
    $filecrypt->decryptFileChunks('encrypted.gif', 'decrypted.gif', $key);
?>
于 2013-12-06T00:55:30.867 に答える