Циклические сдвиги и криптопримитив enRUPT

Читая статьи с HabrHabr по одному из самых странных языков программирования (называется J, если кому-то интересно), я встретил в комментариях описание очень простого и компактного алгоритма шифрования под названием enRUPT.

Меня заинтерсовало то, что этот алгоритм, а если быть точным, криптопримитив (т.е элементарную криптографическую операцию) можно описать буквально в несколько строк.

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

В стандартной библиотеке D в модуле core.bitop есть такие операции, которые носят названия rol и ror соответственно, но их реализация заточена под сдвиги с константными значениями и параметр, управляющей величиной сдвига имеет фиксированную типизацию (к сожалению, не помню какой там тип, но точно знаю, что один из беззнаковых). Именно последнее обстоятельство лишает гибкости примитивы rol и ror, что приводит к необходимости создать свои версии этих функций.

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

import std.stdio;

// https://www.google.com/amp/s/www.geeksforgeeks.org/rotate-bits-of-an-integer/amp/
T rol(T)(T value, ulong shift)
{
	return (value << shift) | (value >> (T.sizeof - shift));
}

T ror(T)(T value, ulong shift)
{
	return (value >> shift) | (value << (T.sizeof - shift));
}

Теперь реализация криптопримитива enRUPT, содержащего две функции для режима блочного шифрования и выполняющих шифрование/расшифровывания, выполняется почти буквальной трансляцией кода с C (с учетом особенностей языка программирования D):

uint er1(uint[] x, uint r, uint k)
{
	return ror(2 * x[(r - 1) % x.length] ^ x[(r + 1) % x.length] ^ k ^ r, 8) * 9 ^ k;
}

auto enRUPT(ref uint[] x, ref uint[] key)
{
    uint s = 4, n = cast(uint) (s * (2 * x.length + key.length));
    for (uint r = 1; r <= n; r++)
    	x[r % x.length] ^= er1(x, r, key[r % key.length]);
}

auto unRUPT (ref uint[] x, ref uint[] key)
{
    uint s = 4, n = cast(uint) (s * (2 * x.length + key.length));
    for (uint r = n; r   ; r--) 
    	x[r % x.length] ^= er1(x, r, key[r % key.length]);
}

Полный код примера:

import std.stdio;

// https://www.google.com/amp/s/www.geeksforgeeks.org/rotate-bits-of-an-integer/amp/
T rol(T)(T value, ulong shift)
{
	return (value << shift) | (value >> (T.sizeof - shift));
}

T ror(T)(T value, ulong shift)
{
	return (value >> shift) | (value << (T.sizeof - shift));
}

uint er1(uint[] x, uint r, uint k)
{
	return ror(2 * x[(r - 1) % x.length] ^ x[(r + 1) % x.length] ^ k ^ r, 8) * 9 ^ k;
}

auto enRUPT(ref uint[] x, ref uint[] key)
{
    uint s = 4, n = cast(uint) (s * (2 * x.length + key.length));
    for (uint r = 1; r <= n; r++)
    	x[r % x.length] ^= er1(x, r, key[r % key.length]);
}

auto unRUPT (ref uint[] x, ref uint[] key)
{
    uint s = 4, n = cast(uint) (s * (2 * x.length + key.length));
    for (uint r = n; r   ; r--) 
    	x[r % x.length] ^= er1(x, r, key[r % key.length]);
}

void main()
{
	uint[] m = [0xab, 0xcd, 0xef, 0x01];
	uint[] k = [0x00, 0x01, 0x02, 0x03, 0x04];
	writeln(m);	
	enRUPT(m, k);
	writeln(m);
	unRUPT(m, k);
	writeln(m);
}

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

Добавить комментарий