0

これは重複した投稿ではありません。なぜなら、私はどこを見ても答えが見つからないからです。その部分的な復号化について。満タンではない。

PHP についてはよく知っていますが、暗号化についてはほとんど知りません。暗号化されたファイルのキーと iv を知っています。ファイル全体は正常に復号化されていますが、途中から部分的なファイルを復号化しようとすると、実際の問題が発生します。

ファイルの最初の 128kb または 256kb またはファイルの先頭から任意の長さを復号化しようとすると、正常に復号化されます。しかし、途中から開始すると、復号化されず、意味不明な出力が得られます。

ファイルの最初の 100 バイトの例をここに投稿します。

暗号化は AES 128 ビット CTR モードです。

PHP の mdecrypt_generic 関数と mcrypt_decrypt 関数の両方を使用しましたが、成功しませんでした。

使用したコード:

$chunk2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, base64_decode($mega_key), $data, 'ctr', base64_decode($mega_iv));
echo base64_encode($data) .'<br />'. base64_encode($chunk2);

結果:

9PX2fU83NF3hLc+HFdyHkqfxC4bHWKUQwQHJkNVnYbKCIQrhlHvTKtz8T3Bb0TgBkyBoGHnDCzZs3bu54KLQ8Bv0lzrTVJbzJY5msBfcy7Zi2Z/fLoMm+nvqdGPTNR0uwv45xJ8=
MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTE=

ご覧のように。復号化後の結果は、数字の 1が連続して含まれるファイルの最初の 100 バイトです。ファイルは JavaScript を使用して Mega.co.nz によって暗号化されます。Mega のドキュメントによると、ファイルは部分的な暗号化/復号化のためにチャンクで暗号化されています。

ファイル暗号化

MEGA は、クライアント側の暗号化/復号化を使用して、ファイル転送とストレージをエンドツーエンドで保護します。クライアントから受信したデータは保存され、逐語的に送信されます。サーバーは、着信ユーザー ファイルの暗号化を復号化も再暗号化も検証もしません。すべての暗号化処理は、エンド ユーザーの管理下にあります。整合性がチェックされた部分読み取りを可能にするために、ファイルは一連のチャンクとして扱われます。サーバー側の処理を簡素化するために、部分アップロードはチャンク境界でのみ開始および終了できます。さらに、部分的なダウンロードは、同じ基準を満たす場合にのみ完全性をチェックできます。チャンク境界は、0 / 128K / 384K / 768K / 1280K / 1920K / 2688K / 3584K / 4608K / の位置にあります。(1024 KB ごと) / EOF

この関数を使用して、ファイルのチャンク境界を計算しています。

public function get_chunks($size)
{
    $chunks = array();
    $p = $pp = 0;

    for ($i = 1; $i <= 8 && $p < $size - $i * 0x20000; $i++) {
        $chunks[$p] = $i * 0x20000;
        $pp = $p;
        $p += $chunks[$p];
    }

    while ($p < $size) {
        $chunks[$p] = 0x100000;
        $pp = $p;
        $p += $chunks[$p];
    }

    $chunks[$pp] = ($size - $pp);
    if (!$chunks[$pp])
    {
        unset($chunks[$pp]);
    }

    return $chunks;
}

2 番目のチャンクを個別に復号化しようとしましたが、失敗します。明らかな理由で 128kb のチャンクをここに投稿することはできませんが、2 バイト目から 100 バイト目までのチャンクを示します。これは同じコードの結果です:

使用したコード:

$chunk2 = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, base64_decode($mega_key), $data, 'ctr', base64_decode($mega_iv));
echo base64_encode($data) .'<br />'. base64_encode($chunk2);

結果:

9fZ9Tzc0XeEtz4cV3IeSp/ELhsdYpRDBAcmQ1WdhsoIhCuGUe9Mq3PxPcFvROAGTIGgYecMLNmzdu7ngotDwG/SXOtNUlvMljmawF9zLtmLZn98ugyb6e+p0Y9M1HS7C/jnEnw==
MDK6A0kyWI3903mj+GokBGfLvHCuzITg8flodIM34gGSGtpE3pnIxxGCDhq72AijgnlBUIv5DGuAVzNoc0MR2t5SnNi281TnmtnnlvomTOWKd3HAnJTtsKCvJoHXGQLdDfbMag==

結果は同じですmcrypt_module_open('rijndael-128', '', 'ctr', '');

並列接続/再開サポートをサポートする Mega 用のオープン ソース ダウンロード マネージャーをコーディングしようとしているため、ファイルを部分的に復号化する必要があります。

ファイルのストリーミングを許可するには、その場でファイルを復号化する必要があるため、ダウンロード後に復号化することは問題外です。

Mega の Web サイトでは、独自のダウンロード インターフェイスが複数の接続を使用し、ファイルをチャンクでダウンロードします。複数の接続を使用して Mega からダウンロードし、サポートを再開できる別の Web サービスがあります。

ブラウザ/ダウンロード マネージャからの HTTP Range ヘッダー リクエストをサポートするには、部分ファイルを復号化する必要があります。範囲要求が 2 番目または 3 番目のブロックに含まれる場合、最初からファイルを復号化せずに、そのブロックを復号化してクライアントに送信できる必要があります。

それは可能ですか?一部のWebサイトがすでにそれを行っているためです。

4

2 に答える 2

1

わかりました。その場で部分的なコンテンツを復号化する方法を見つけました。Range から部分的なデータを復号化しようとしたときに (Web プロキシを作成するために)、この問題が発生しました。ファイル全体を(位置0から)ダウンロードしても問題がないことがわかりました。例 :

while($_total_dled != $content_length) {
        $raw = fgets($socket, 1024);
        $data = mdecrypt_generic($this->cipher, $raw);
        echo $data;
}

しかし、 pos xからファイルの読み取りを開始すると (受信した場合のように : Range x-) 、 mdecrypt_generic は以前に (x-1) 回実行されていないため、失敗します。だから私はこれを試します:

for($i=0;$i<$range["start"];$i++) {
     mdecrypt_generic($this->cipher, "0");
}

1文字(x-1)回復号化するだけです。そして、whileループのある部分。そして、それは機能します。この繰り返しを関連するカウンターとリンクできるかもしれません。

これが人々を助けることを願っています。

于 2014-08-22T22:25:02.620 に答える
0

チャンクの境界 (表 + 4608Ki を超える単純な計算として与えられる) で多くの計算を行っており、新しい IV に到達するための計算を行っていないように思えます。

IV はランダムナンスにブロックカウンターを加えたものです。したがって、特定のチャンクの新しい「IV」を計算するには、次のようにする必要があります。

  1. ノンスを上位 (左) バイトにシフトして初期カウンターを作成する
  2. チャンクの下限を取得する
  3. 下限をブロックサイズで割る
  4. 結果の数値を初期カウンターに加算または XOR (最初の 2^64 ブロックも同様)
  5. それを使用して暗号を初期化します

その後、復号化できるはずです。

于 2014-07-20T11:10:06.367 に答える