1

1MB のテスト ファイルがあり、最初からではなく 500KB から解読したいと考えています。ファイルの 500 KB から正確に開始する必要はありません。最初でない限り、任意のチャンクの先頭から開始できます。その方法を学びたいだけです。

このスクリプトを使用すると、ファイルが 0KB から始まる限り、ファイルを復号化できます。

$file = file_get_contents("file.dat");
$aeskey = base64_decode("sVv2g7boc/pzCDepDfV1VA==");
$iv = base64_decode("A5chWWE3D4cAAAAAAAAAAA==");

$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ctr', '');
mcrypt_generic_init($td, $aeskey, $iv);

echo mdecrypt_generic($td, $file);

少なくとも可能であれば、誰かが私に説明してもらえますか?

4

1 に答える 1

2

CTR モードでは、カウンター (AES の場合は 128 ビット) が暗号化されてキー ストリームが生成され、それがプレーンテキストまたは暗号文と XOR されます。通常、IV は 64 ビットまたは 96 ビットであると想定され、残りのビットは実際には 0 に設定されます。最初の 64 ビットまたは 96 ビットはnonceと呼ばれます。

nonce のサイズは、多数のタイム パッドを作成せずに一度に暗号化できるデータの量を決定します。nonce が大きいほど、安全なメッセージの長さは短くなりますが、2 つの nonce がランダムに生成された場合に衝突する可能性も低くなります。ナンスの大きさの仕様がないため、多くのフレームワークはナンスのサイズを特定のサイズに制限していません。

mcrypt ではノンスにフル ブロック サイズを使用できます。

あなたはできる

  1. 最初から使っていたIVを取って、
  2. その IV を大きな整数として解析します (PHP の整数型には適合しません)。
  3. スキップするブロック数 (AES の場合は 16 バイト ブロック) を表す数値をそれに追加し、
  4. 数値をバイナリ表現に変換し、
  5. 後のバイトから復号化を開始します。

手順 2 ~ 4 はadd、次のコードの関数によって実行されます。

大きなファイルがあり、バイト 512 (簡単にするためにブロック サイズの倍数) から復号化したい場合を考えてみましょう。IVに512/16=32を追加します。

コード例を次に示します。

<?php
$d = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
$k = "k0k1k2k3k4k5k6k7"; // 16 byte AES key
$bs = 16; // 16 byte block size

$iv = mcrypt_create_iv($bs);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ctr', '');
mcrypt_generic_init($td, $k, $iv);
$ct = mcrypt_generic($td, $d);

$dec_offset = 32;
$ct_slice = substr($ct, $dec_offset);

$iv_slice = add($iv, $dec_offset / $bs);

$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', 'ctr', '');
mcrypt_generic_init($td, $k, $iv_slice);
$d_slice = mdecrypt_generic($td, $ct_slice);

var_dump($d_slice);

function add($big_num_str, $to_add){
    $big_num = str_split(strrev($big_num_str));
    for($i = 0; $i < count($big_num) ; $i++){
        $tmp = ord($big_num[$i]) + $to_add;
        $big_num[$i] = $tmp % 256;
        $to_add = floor( $tmp / 256 );
    }
    while($to_add){
        $big_num[$i++] = $to_add % 256;
        $to_add = floor( $to_add / 256 );
    }
    for($i = 0; $i < count($big_num) ; $i++){
        $big_num[$i] = chr($big_num[$i]);
    }
    return strrev(implode('', $big_num) );
}

出力:

文字列(32) "101112131415161718191a1b1c1d1e1f"

これは、PHP の OpenSSL 拡張機能でもまったく同じように機能します。これがコードです。


もちろん、ブロック境界で始まらないチャンクを取得したい場合、これはもう少し複雑になります。ブロックを早めに開始し、余分なバイトを削除する必要があります。

于 2016-03-14T20:57:00.477 に答える