Seal
Seal (от англ. Simple Encrypting Algorithm — Простой алгоритм шифрования) — авторский блочный шифр, основанный на алгоритме ESCK-7. В отличие от ESCK-7, в котором шифрующая таблица является одновременно и ключом шифрования, что требует его специальной генерации, в алгоритме Seal применяется заранее определённая и неизменная шифрующая таблица, а ключ «нормального» размера (128 или 256 бит) применяется отдельно. Шифр основан на довольно несложных принципах, а также прост в реализации: функция шифрования состоит всего из 12 значимых строк кода.
Принципы
Само шифрование осуществляется путём многократного прибавления к шифруемому элементу чисел из шифрующей таблицы и выполнения циклических побитовых сдвигов. Чтобы результат сложения зависел от порядка прибавляемых чисел, сдвиги выполняются на разное количество бит, а также чередуются сдвиги до сложения и после. Кроме того, в некоторых случаях обычное прибавление заменяется операцией XOR (исключающее ИЛИ), а в других — дополнительно выполняется NOT (побитовое НЕ).
Один из важнейших принципов: номера прибавляемых чисел из шифрующей таблицы определяются в процессе шифрования и зависят от заданного ключа шифрования, номера блока и значения соседнего с шифруемым элемента блока. Поскольку шифрование выполняется в несколько проходов (циклов), в каждом из них значения элементов блока меняются и это влияет на шифрование в следующем проходе (цикле). Количество циклов нефиксированное и может принимать любое значение, заданное пользователем.
Реализация
Алгоритм состоит из нескольких функций, объединённых в пространство имён Seal. Функция EncryptBlock() шифрует 128-битный блок 128-битным ключом, каждый из которых представлен массивом из двух 64-битных чисел (типа uint64_t). Для шифрования байтового блока (16 чисел типа uint8_t) представлен дополнительный вариант одноимённой функции, загружающий байты в «стандартный» массив перед шифрованием и выгружающий после. Функции DecryptBlock() позволяют расшифровать блок также в виде стандартного или байтового массива.
Функции EncryptBlock256() и DecryptBlock256() позволяют шифровать и расшифровать 128-битный блок удлинённым 256-битным ключом (4 числа типа uint64_t). Для шифрования блока 256-битным ключом этот ключ разбивается на две половины по 128 бит и блок шифруется обычной функцией EncryptBlock() вначале первой половиной, потом второй и потом снова первой. Поскольку шифрование выполняется с заданным количеством циклов, в случае 256-битного ключа треть циклов отводится для шифрования первой его половиной, ещё треть для второй, а остаток — опять для первой.
Один проход (цикл) шифрования блока очень напоминает таковой в ESCK-7. Для каждого из двух 64-битных элементов блока вычисляется 64-битная адресная переменная путём сложения со сдвигами значений соседнего элемента, номера блока и текущего элемента ключа. Полученное значение разбивается на восемь 8-битных номеров, по которым и берутся числа из шифрующей таблицы. Далее эти числа прибавляются (+/XOR) к шифруемому элементу блока с выполнением циклических сдвигов над самими числами или результатами сложения.
Генерация ключа и режимы шифрования
В отличие от ESCK-7, в Seal не предусмотрен способ генерации ключа по умолчанию, поэтому 128- или 256-битный ключ можно (и нужно) генерировать любым доступным способом (в том числе на основе хеширования пароля, например, по стандарту PBKDF2), не забывая приводить его к виду массива из 2 или 4 чисел типа uint64_t. Специфические режимы шифрования также необходимо реализовывать отдельно, однако при шифровании каждого блока можно указывать его номер (по умолчанию равен 0), что будет оказывать влияние и вносить различия в результаты шифрования разных блоков.
SealFile
SealFile (sealfile.cpp) является консольной/терминальной программой для шифрования и расшифровки файлов по алгоритму Seal и представляет собой пример применения алгоритма. В программе реализован простой способ генерации 256-битного ключа по одному или нескольким паролям, чтение файла в буфер с разбивкой его на блоки и их шифрование или расшифровка сгенерированным ключом с применением счётчика блоков. Также реализован подсчёт контрольной суммы с её шифрованием перед сохранением в файл.
Критические изменения алгоритма
25.04.2025. В функции шифрования блока (EncryptBlock) прибавление константы заменено прибавлением номера цикла (в DecryptBlock - отниманием).