Как libgcrypt увеличивает счетчик для режима CTR? - PullRequest
0 голосов
/ 27 декабря 2018

У меня есть файл, зашифрованный AES-256 с использованием реализации режима CTR в libgcrypt.Я хочу иметь возможность дешифровать файл по частям (например, дешифрование блоков 5-10 из 20 блоков без дешифрования всего файла).

Я знаю, что используя режим CTR, я смогу сделать это,Все, что мне нужно, это знать правильный счетчик.Проблема заключается в том, что все, что у меня есть, это начальный счетчик для блока 0. Если я хочу, например, дешифровать блок 5, мне нужен другой счетчик, тот, который достигается путем выполнения некоторого действия с начальным счетчиком для каждого блока из 0до 5.

Я не могу найти API, который предоставляет libgcrypt, чтобы вычислить счетчик для более поздних блоков с учетом начального счетчика.

Как вычислить счетчик для более поздних блоков (например, блок № 5) с учетом счетчика блока № 0?

1 Ответ

0 голосов
/ 27 декабря 2018

Если есть сомнения, перейдите к источнику .Вот код в реализации общего CTR-режима gcrypt (_gcry_cipher_ctr_encrypt() in cipher-ctr.c), который увеличивает счетчик:

for (i = blocksize; i > 0; i--)
  {
    c->u_ctr.ctr[i-1]++;
    if (c->u_ctr.ctr[i-1] != 0)
      break;
  }

Существуют другие, более оптимизированные реализации увеличения счетчика, найденные в других местах в источнике libgcrypt.например, в различных реализациях шифрования быстрого массового CTR для конкретного шифра, но этот универсальный вариант оказывается приятным и читаемым.(Конечно, все эти альтернативные реализации в любом случае должны генерировать одинаковую последовательность значений счетчиков, чтобы gcrypt оставался совместимым с самим собой.)

ОК, так что же он делает на самом деле?

ХорошоЕсли посмотреть на контекст (или, более конкретно, cipher-internal.h), становится ясно, что c->u_ctr.ctr - это массив blocksize байтов без знака (где blocksize равно 16 байтов для AES).Приведенный выше код увеличивает свой последний байт на единицу и проверяет, будет ли результат обернут до нуля.Если это не так, он останавливается;если он сделал перенос, код затем перемещается к второму-последнему байту, увеличивает его, проверяет, является ли он обернутым, и продолжает цикл, пока не найдет байт, который не переносится при увеличении, или он увеличилсявсе blocksize байт.

Так, например, если исходное значение счетчика было {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, то после увеличения оно станет {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}.При повторном увеличении оно станет {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2}, затем {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3} и т. Д. До {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255}, после чего следующее значение счетчика будет {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0} (и после этого {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3} и т. д.).

Конечно, на самом деле это просто арифметически увеличивать одно (blocksize × 8) -битное целое число, хранящееся в памяти в big-endian порядок байтов.

...