Если есть сомнения, перейдите к источнику .Вот код в реализации общего 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 порядок байтов.