AES 128 бит CTR частичная расшифровка файлов с помощью PHP
Это не дублированный пост, потому что я посмотрел везде и не могу найти ответ на этот вопрос. Это о частичной расшифровке. Не полный.
Я хорошо знаю PHP, но мало знаю о криптографии. Я знаю ключ и iv зашифрованного файла. Файл полностью расшифровывается, но реальная проблема возникает, когда я пытаюсь расшифровать частичный файл с середины.
Он прекрасно расшифровывается, когда я пытаюсь расшифровать первые 128 КБ файла или 256 КБ или любую длину от начала файла. но когда я начинаю с середины, он не расшифровывает, а выдает бессмысленный вывод.
Я опубликую здесь пример первых 100 байтов файла.
Шифрование - 128-битный режим CTR AES.
Я использовал функции 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=
Как вы видете. после дешифрования результатом являются первые 100 байтов файла, содержащего цифру 1 в серии. Файл зашифрован Mega.co.nz с использованием JavaScript. Согласно документации в Mega, файл был зашифрован кусками для частичного шифрования / дешифрования.
Шифрование файлов
MEGA использует шифрование / дешифрование на стороне клиента для сквозной защиты при передаче и хранении файлов. Данные, полученные от клиентов, хранятся и передаются дословно; серверы не дешифруют, не перешифруют и не проверяют шифрование входящих пользовательских файлов. Вся криптографическая обработка находится под контролем конечного пользователя. Чтобы обеспечить частичное чтение с проверкой целостности, файл обрабатывается как серия фрагментов. Чтобы упростить обработку на стороне сервера, частичные загрузки могут начинаться и заканчиваться только на границе фрагмента. Кроме того, частичные загрузки могут быть проверены на целостность, только если они соответствуют одному и тому же критерию. Границы фрагментов расположены в следующих положениях: 0 / 128K / 384K / 768K / 1280K / 1920K / 2688K / 3584K / 4608K /. (каждые 1024 КБ) / 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-й блок по отдельности, это не удается. Я не могу разместить чанк 128 КБ здесь по понятным причинам, но я покажу вам чанк, начиная со 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 их собственный интерфейс загрузки использует несколько подключений и загружает файл порциями, а есть еще один веб-сервис, который позволяет загружать из Mega несколько подключений и поддерживать возобновление.
Мне нужно расшифровать частичный файл для поддержки запросов заголовка HTTP Range от браузера / менеджеров загрузки. Если запрос диапазона попадает во 2-й или 3-й блок, мне нужно иметь возможность расшифровать этот блок и отправить его клиенту, не расшифровывая файл с самого начала.
Это вообще возможно? Это должно быть потому, что какой-то сайт уже сделал это.
2 ответа
Хорошо, я нашел решение о расшифровке частичного контента на лету. У меня была эта проблема, когда я пытался расшифровать частичные данные из Range (для создания веб-прокси). Я обнаружил, что, если я загружаю весь файл (с позиции 0 так), нет проблем. Пример:
while($_total_dled != $content_length) {
$raw = fgets($socket, 1024);
$data = mdecrypt_generic($this->cipher, $raw);
echo $data;
}
НО, если я начну читать файл с позиции x (как если бы я получил: Range x-), mdecrypt_generic завершится ошибкой, потому что он не был выполнен (x-1) раз раньше. Итак, я пытаюсь это:
for($i=0;$i<$range["start"];$i++) {
mdecrypt_generic($this->cipher, "0");
}
Просто нужно расшифровать один символ (х-1) раз. и затем часть с циклом while. И это работает. Может быть, мы можем связать эту итерацию с соответствующим счетчиком.
Надеюсь, это поможет людям.
Сдается мне, что вы делаете много вычислений на границах чанка (которые приведены в виде таблицы + простой расчет на 4608Ki) и не рассчитываете, чтобы добраться до нового IV.
IV - это просто случайный одноразовый номер плюс счетчик блоков. Таким образом, чтобы вычислить новый "IV" для конкретного чанка, вам нужно сделать:
- создать начальный счетчик, сдвинув одноразовый номер в старшие (левые) байты
- получить нижнюю границу куска
- разделить нижнюю границу на размер блока
- добавить или XOR (то же самое для первых 2^64 блоков) результирующее число к начальному счетчику
- инициализировать ваш шифр с ним
Тогда вы должны быть в состоянии расшифровать.