Алгоритм шифрования XTEA

Иногда возникает потребность в реализации достаточно быстрого, но вместе с тем довольно простого алгоритма блочного шифрования, который не был бы слишком критичен к ресурсам и при этом не был бы слишком строгим криптографическим методом.

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

Об алгоритме XTEA вы можете прочесть в Википедии, а сам код выглядит довольно просто и представляет собой портированную с Си версию, описанную в статье от самих авторов алгоритма:

class XTEA
{
	static uint[2] encrypt(uint[2] block, uint[2] key, uint rounds = 64)
	{
        uint v0 = block[0], v1 = block[1], sum = 0, delta=0x9E3779B9;
	    
	    for (uint i = 0; i < rounds; i++) 
	    {
	        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
	        sum += delta;
	        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
	    }
    	
    	block[0] = v0; block[1] = v1;

    	return block;
	}

	static uint[2] decrypt(uint[2] block, uint[2] key, uint rounds = 64)
	{
	    uint v0 = block[0], v1 = block[1], delta = 0x9E3779B9, sum = delta * rounds;
	    
	    for (uint i=0; i < rounds; i++) 
	    {
	        v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
	        sum -= delta;
	        v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
	    }
	    
	    block[0] = v0; block[1] = v1;

	    return block;
	}
}

abstract class ExtendedTea
{
	private
	{
		enum uint DELTA = 0x9E3779B9;
		static uint rol(uint base, uint shift)
		{
			uint res;
			shift &= 0x1F;
        	res = (base << shift) | (base >> (32 - shift));
        	return res;
		}
	}
}

class XTEA1 : ExtendedTea
{
	static uint[2] encrypt(uint[2] block, uint[4] key, uint rounds)
	{
		uint y, z, sum = 0;
		
		y = block[0] + key[0];
		z = block[1] + key[1];

		for (uint i = 0; i < rounds; i++) 
		{
			y += ((z << 4) ^ (z >> 5)) + (z ^ sum) + rol(key[sum & 3], z);
			sum += DELTA;
			z += ((y << 4) ^ (y >> 5)) + (y ^ sum) + rol(key[(sum >> 11) & 3], y);
		}

		block[0] = y ^ key[2];
		block[1] = z ^ key[3];

		return block;
	}

	static uint[2] decrypt(uint[2] block, uint[4] key, uint rounds)
	{
		uint y, z, sum = DELTA * rounds;
		
		z = block[1] ^ key[3];
		y = block[0] ^ key[2];
		
		for (uint i = 0; i < rounds; i++) 
		{
			z -= ((y << 4) ^ (y >> 5)) + (y ^ sum) + rol(key[(sum >> 11) & 3], y);
			sum -= DELTA;
			y -= ((z << 4) ^ (z >> 5)) + (z ^ sum) + rol(key[sum & 3], z);
		
		}
		
		block[1] = z - key[1];
		block[0] = y - key[0];

		return block;
	}
}

class XTEA2 : ExtendedTea
{
	static uint[4] encrypt(uint[4] block, uint[4] key, uint rounds)
	{
		uint a, b, c, d, sum = 0, t;
		a = block[0];
		b = block[1] + key[0];
		c = block[2];
		d = block[3] + key[1];
		
		for (uint i = 0; i < rounds; i++) 
		{
			a += ((b << 4) ^ (b >> 5)) + (d ^ sum) + rol(key[sum & 3], b);
			sum += DELTA;
			c += ((d << 4) ^ (d >> 5)) + (b ^ sum) + rol(key[(sum >> 11) & 3], d);
			t = a; a = b; b = c; c = d; d = t;
		}
		
		block[0] = a ^ key[2];
		block[1] = b;
		block[2] = c ^ key[3];
		block[3] = d;

		return block;
	}

	static uint[4] decrypt(uint[4] block, uint[4] key, uint rounds)
	{
		uint a, b, c, d, t, sum = DELTA * rounds;
		d = block[3];
		c = block[2] ^ key[3];
		b = block[1];
		a = block[0] ^ key[2];
		
		for (uint i = 0; i < rounds; i++) 
		{
			t = d; d = c; c = b; b = a; a = t;
			c -= ((d << 4) ^ (d >> 5)) + (b ^ sum) + rol(key[(sum >> 11) & 3], d);
			sum -= DELTA;
			a -= ((b << 4) ^ (b >> 5)) + (d ^ sum) + rol(key[sum & 3], b);
		}

		block[0] = a;
		block[1] = b - key[0];
		block[2] = c;
		block[3] = d - key[1];

		return block;
	}
}

class XTEA3 : ExtendedTea
{
	static uint[4] encrypt(uint[4] block, uint[8] key, uint rounds = 64)
	{
		uint a, b, c, d, sum = 0, t;
		a = block[0] + key[0];
		b = block[1] + key[1];
		c = block[2] + key[2];
		d = block[3] + key[3];
		
		for (uint i = 0; i < rounds; i++)
		{
			a += (((b << 4) + rol (key[(sum % 4) + 4], b)) ^ (d + sum) ^ ((b >> 5) + rol (key[sum % 4], b >> 27)));
			sum += DELTA;
		    c += (((d << 4) + rol (key[((sum >> 11) % 4) + 4], d)) ^ (b + sum) ^ ((d >> 5) + rol (key[(sum >> 11) % 4], d >> 27)));
		    t = a; a = b; b = c; c = d; d = t;
		}
		
		block[0] = a ^ key[4];
		block[1] = b ^ key[5];
		block[2] = c ^ key[6];
		block[3] = d ^ key[7];

		return block;
	}
 
	static uint[4] decrypt(uint[4] block, uint[8] key, uint rounds)
	{
	    uint a, b, c, d, t, sum = DELTA * rounds;
		d = block[3] ^ key[7];
		c = block[2] ^ key[6];
		b = block[1] ^ key[5];
		a = block[0] ^ key[4];
		
		for (uint i = 0; i < rounds; i++)
		{
			t = d; d = c; c = b; b = a; a = t;
			c -= (((d << 4) + rol (key[((sum >> 11) % 4) + 4], d)) ^ (b + sum) ^ ((d >> 5) + rol (key[(sum >> 11) % 4], d >> 27)));
	        sum -= DELTA;
			a -= (((b << 4) + rol (key[(sum % 4) + 4], b)) ^ (d + sum) ^ ((b >> 5) + rol (key[sum % 4], b >> 27)));
		 }
		
		block[3] = d - key[3];
		block[2] = c - key[2];
		block[1] = b - key[1];
		block[0] = a - key[0];

		return block;
	}
}

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

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

uint[4] createBlock(ubyte[16] raw)
{
	uint[4] block;

	for (uint i = 0; i < 16; i += 4)
	{
		uint tmp = 0x00000000;
		
		tmp = raw[i] << 24;
		tmp = tmp | (raw[i+1] << 16);
		tmp = tmp | (raw[i+2] << 8);
		tmp = tmp | (raw[i+3]);

		block[i / 4] = tmp;
	}
	return block;
}

ubyte[16] createRaw(uint[4] block)
{
	ubyte[16] raw;
	
	for (int i = 0; i < 4; i++) { raw[i * 4 + 3] = cast(ubyte) (block[i] & 0x000000ff); raw[i * 4 + 2] = cast(ubyte) ((block[i] & 0x0000ff00) >> 8);
		raw[i * 4 + 1] = cast(ubyte) ((block[i] & 0x00ff0000) >> 16);
		raw[i * 4] = cast(ubyte) ((block[i] & 0xff000000) >> 24);
	}

	return raw;
}

Испытаем процедуры шифрования/дешифрования алгоритмом XTEA на примере блока, состоящего из 4 чисел, каждое из которых представляет собой специально применяемое для отладки функций, работающих с байтами, под названием «мертвая корова» (0xdeadbeef):

import std.stdio;

void main()
{
	auto coded = XTEA3.encrypt( 
		[0xdeadbeef, 0xdeadbeef, 0xdeadbeef, 0xdeadbeef], 
		[0x12345678, 0x00ff00ff, 0x1111aaaa, 0x1010ffcc, 0x12345678, 0x00ff00ff, 0x1111aaaa, 0x1010ffcc],
		64
		);
	auto decoded = XTEA3.decrypt(
		coded,
		[0x12345678, 0x00ff00ff, 0x1111aaaa, 0x1010ffcc, 0x12345678, 0x00ff00ff, 0x1111aaaa, 0x1010ffcc],
		64
	);
	writefln("%0.8x%0.8x%0.8x%0.8x",coded[0], coded[1], coded[2], coded[3]);
	writefln("%0.8x%0.8x%0.8x%0.8x",decoded[0], decoded[1], decoded[2], decoded[3]);
}

Вывод программы:

a1e768fda0bb31643c1c3d4bb78bc123
deadbeefdeadbeefdeadbeefdeadbeef

Теперь вы можете использовать данные процедуры, но насколько мне известно, уже существуют эффективные реализации этих алгоритмов на D, но тем не менее, вы все равно можете использовать этот рецепт в том, случае, если вам не нужны сторонние зависимости и вы прекрасно знаете, в каких случаях вы можете использовать данный алгоритм (настоятельно рекомендую ознакомится с описанием алгоритма и книгой «Прикладная криптография» Брюса Шнайера).

 

aquaratixc

Программист-самоучка и программист-любитель

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