1 module xtea.XteaCrypto;
2 
3 /++ 
4  +	XTEA helper type
5  +	see: http://en.wikipedia.org/wiki/XTEA
6 +/
7 public struct XTEA
8 {
9 	/// XTEA delta constant
10 	private enum int DELTA = cast(int)0x9E3779B9;
11 
12 	/// Key - 4 integer
13 	private int[4] m_key;
14 
15 	/// Round to go - 64 are commonly used
16 	private int m_rounds;
17 
18 	/// c'tor
19 	public this(int[4] _key, int _rounds)
20 	{
21 		m_key = _key;
22 		m_rounds = _rounds;
23 	}
24 
25 	/// Encrypt given byte array (length to be crypted must be 8 byte aligned)
26 	public alias Crypt!(EncryptBlock) Encrypt;
27 	/// Decrypt given byte array (length to be crypted must be 8 byte aligned)
28 	public alias Crypt!(DecryptBlock) Decrypt;
29 
30 	///
31 	private const void Crypt(alias T)(byte[] _bytes, size_t _offset=0, long _count=-1)
32 	{
33 		if(_count == -1)
34 			_count = cast(long)(_bytes.length - _offset);
35 
36 		assert(_count % 8 == 0);
37 
38 		for (size_t i = _offset; i < (_offset+_count); i += 8)
39 			T(_bytes, i);
40 	}
41 
42 	/// Encrypt given block of 8 bytes
43 	private const void EncryptBlock(byte[] _bytes, size_t _offset)
44 	{
45 		auto v0 = ReadInt(_bytes, _offset);
46 		auto v1 = ReadInt(_bytes, _offset + 4);
47 
48 		int sum = 0;
49 
50 		foreach (i; 0..m_rounds)
51 		{
52 			v0 += ((v1 << 4 ^ cast(int)(cast(uint)v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]);
53 			sum += DELTA;
54 			v1 += ((v0 << 4 ^ cast(int)(cast(uint)v0 >> 5)) + v0) ^ (sum + m_key[cast(int)(cast(uint)sum >> 11) & 3]);
55 		}
56 
57 		StoreInt(v0, _bytes, _offset);
58 		StoreInt(v1, _bytes, _offset + 4);
59 	}
60 
61 	/// Decrypt given block of 8 bytes
62 	private const void DecryptBlock(byte[] _bytes, size_t _offset)
63 	{
64 		auto v0 = ReadInt(_bytes, _offset);
65 		auto v1 = ReadInt(_bytes, _offset + 4);
66 
67 		auto sum = cast(int)(cast(uint)DELTA * cast(uint)m_rounds);
68 
69 		foreach (i; 0..m_rounds)
70 		{
71 			v1 -= ((v0 << 4 ^ cast(int)(cast(uint)v0 >> 5)) + v0) ^ (sum + m_key[cast(int)(cast(uint)sum >> 11) & 3]);
72 			sum -= DELTA;
73 			v0 -= ((v1 << 4 ^ cast(int)(cast(uint)v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]);
74 		}
75 
76 		StoreInt(v0, _bytes, _offset);
77 		StoreInt(v1, _bytes, _offset + 4);
78 	}
79 
80 	/// Read 32 bit int from buffer
81 	private static int ReadInt(byte[] _bytes, size_t _offset) pure nothrow
82 	{
83 		return (((_bytes[_offset++] & 0xff) << 0)
84 				| ((_bytes[_offset++] & 0xff) << 8)
85 				| ((_bytes[_offset++] & 0xff) << 16)
86 				| ((_bytes[_offset] & 0xff) << 24));
87 	}
88 
89 	/// Write 32 bit int from buffer
90 	private static void StoreInt(int _value, byte[] _bytes, size_t _offset) pure nothrow
91 	{
92 		auto unsignedValue = cast(uint)_value;
93 		_bytes[_offset++] = cast(byte)(unsignedValue >> 0);
94 		_bytes[_offset++] = cast(byte)(unsignedValue >> 8);
95 		_bytes[_offset++] = cast(byte)(unsignedValue >> 16);
96 		_bytes[_offset] = cast(byte)(unsignedValue >> 24);
97 	}
98 }