шифрование — расшифровывает случайный кусок зашифрованного файла AES-CTR в PHP mcrypt

У меня есть тестовый файл объемом 1 МБ, и я хочу расшифровать его, начиная с 500 КБ, а не с самого начала. Он не должен начинаться точно с 500 КБ файла, он может начинаться с начала любого фрагмента, если он не первый, я просто хочу узнать, как это сделать.

С помощью этого скрипта я могу расшифровать файл, если он начинается с 0 КБ.

$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);

Может ли кто-нибудь объяснить мне, если это возможно?

1

Решение

В Режим CTR, счетчик (128 бит для AES) шифруется для создания потока ключей, который затем XOR с открытым текстом или зашифрованным текстом. Обычно предполагается, что IV является 64-битным или 96-битным, а оставшиеся биты фактически устанавливаются в 0. Вызываются начальные 64 или 96-битные данное время.

Размер одноразового номера определяет, сколько данных можно зашифровать за один раз, не создавая многократную временную площадку: чем больше одноразовый номер, тем меньше безопасная длина сообщения, но также ниже вероятность коллизий двух одноразовых номеров, когда они генерируются случайным образом. Поскольку не указано, насколько велик одноразовый номер, многие фреймворки не ограничивают размер одноразового номера конкретным размером.

Вы можете использовать полный размер блока для одноразового номера в mcrypt.

Вы можете

  1. возьмите IV, который использовался с самого начала,
  2. проанализировать, что IV как большое целое число (оно не вписывается в целочисленный тип PHP),
  3. добавьте к нему число, представляющее столько блоков (16 байтных блоков для AES), сколько вы хотите пропускать,
  4. преобразовать число обратно в двоичное представление и
  5. начать расшифровку с более позднего байта.

Шаги 2-4 выполняются add функция в следующем коде.

Допустим, у вас есть большой файл, но вы хотите расшифровать его из байта 512 (кратного размеру блока для простоты). Вы бы добавили 512/16 = 32 до IV.

Вот пример кода:

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

Это также работает точно так же для расширения OpenSSL в PHP. Вот это код.


Конечно, это будет немного сложнее, если вы хотите получить фрагмент, который начинается не на границе блока. Вы должны начать блок раньше и удалить лишние байты.

2

Другие решения

Других решений пока нет …