1 module xtea.XteaCrypto;
2 @safe:
3 nothrow:
4 pure:
5 
6 ubyte[] encrypt(XTEA crypto, const(ubyte)[] m)
7 {
8 	auto ans = m.dup;
9 	crypto.Encrypt(ans);
10 	return ans;
11 }
12 unittest
13 {
14 	enum sourceData = cast(ubyte[])[6, 2, 87, 66, 77, 289, 623, 39823];
15 	enum encrypted = XTEA([1,2,3,4], 64).encrypt(sourceData);
16 	import std.algorithm:equal;
17 	static assert(encrypted.equal([49, 144, 90, 128, 35, 56, 194, 0]));
18 }
19 
20 ubyte[] decrypt(XTEA crypto, const(ubyte)[] m) {
21 	auto ans = m.dup;
22 	crypto.Decrypt(ans);
23 	return ans;
24 }
25 unittest
26 {
27 	enum sourceData = cast(ubyte[])[6, 2, 87, 66, 77, 289, 623, 39823];
28 	enum encrypted = cast(ubyte[])[49, 144, 90, 128, 35, 56, 194, 0];
29 	enum dencrypted = XTEA([1,2,3,4], 64).decrypt(encrypted);
30 	import std.algorithm:equal;
31 	static assert(dencrypted.equal(sourceData));
32 }
33 // Coverage %
34 unittest {
35 	enum sourceData = cast(ubyte[])[6, 2, 87, 66, 77, 289, 623, 39823];
36 	enum crypto = XTEA([1,2,3,4], 64);
37 	auto runtime = crypto.decrypt(crypto.encrypt(sourceData));
38 	import std.algorithm:equal;
39 	assert(runtime.equal(sourceData));
40 }
41 
42 /++ 
43  +	XTEA helper type
44  +	see: http://en.wikipedia.org/wiki/XTEA
45 +/
46 public struct XTEA
47 {
48 @safe:
49 nothrow:
50 pure:
51 	/// XTEA delta constant
52 	private enum int DELTA = cast(int)0x9E3779B9;
53 
54 	/// Key - 4 integer
55 	private int[4] m_key;
56 
57 	/// Round to go - 64 are commonly used
58 	private int m_rounds;
59 
60 	/// c'tor
61 	public this(int[4] _key, int _rounds)
62 	{
63 		m_key = _key;
64 		m_rounds = _rounds;
65 	}
66 
67 	/// Encrypt given ubyte array (length to be crypted must be 8 ubyte aligned)
68 	public alias Crypt!(EncryptBlock) Encrypt;
69 	/// Decrypt given ubyte array (length to be crypted must be 8 ubyte aligned)
70 	public alias Crypt!(DecryptBlock) Decrypt;
71 
72 	///
73 	private const void Crypt(alias T)(ubyte[] _ubytes, size_t _offset=0, long _count=-1)
74 	{
75 		if(_count == -1)
76 			_count = cast(long)(_ubytes.length - _offset);
77 
78 		assert(_count % 8 == 0);
79 
80 		for (size_t i = _offset; i < (_offset+_count); i += 8)
81 			T(_ubytes, i);
82 	}
83 
84 	/// Encrypt given block of 8 ubytes
85 	private const void EncryptBlock(ubyte[] _ubytes, size_t _offset)
86 	{
87 		auto v0 = ReadInt(_ubytes, _offset);
88 		auto v1 = ReadInt(_ubytes, _offset + 4);
89 
90 		int sum = 0;
91 
92 		foreach (i; 0..m_rounds)
93 		{
94 			v0 += ((v1 << 4 ^ cast(int)(cast(uint)v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]);
95 			sum += DELTA;
96 			v1 += ((v0 << 4 ^ cast(int)(cast(uint)v0 >> 5)) + v0) ^ (sum + m_key[cast(int)(cast(uint)sum >> 11) & 3]);
97 		}
98 
99 		StoreInt(v0, _ubytes, _offset);
100 		StoreInt(v1, _ubytes, _offset + 4);
101 	}
102 
103 	/// Decrypt given block of 8 ubytes
104 	private const void DecryptBlock(ubyte[] _ubytes, size_t _offset)
105 	{
106 		auto v0 = ReadInt(_ubytes, _offset);
107 		auto v1 = ReadInt(_ubytes, _offset + 4);
108 
109 		auto sum = cast(int)(cast(uint)DELTA * cast(uint)m_rounds);
110 
111 		foreach (i; 0..m_rounds)
112 		{
113 			v1 -= ((v0 << 4 ^ cast(int)(cast(uint)v0 >> 5)) + v0) ^ (sum + m_key[cast(int)(cast(uint)sum >> 11) & 3]);
114 			sum -= DELTA;
115 			v0 -= ((v1 << 4 ^ cast(int)(cast(uint)v1 >> 5)) + v1) ^ (sum + m_key[sum & 3]);
116 		}
117 
118 		StoreInt(v0, _ubytes, _offset);
119 		StoreInt(v1, _ubytes, _offset + 4);
120 	}
121 
122 	/// Read 32 bit int from buffer
123 	private static int ReadInt(ubyte[] _ubytes, size_t _offset)
124 	{
125 		return (((_ubytes[_offset++] & 0xff) << 0)
126 				| ((_ubytes[_offset++] & 0xff) << 8)
127 				| ((_ubytes[_offset++] & 0xff) << 16)
128 				| ((_ubytes[_offset] & 0xff) << 24));
129 	}
130 
131 	/// Write 32 bit int from buffer
132 	private static void StoreInt(int _value, ubyte[] _ubytes, size_t _offset)
133 	{
134 		auto unsignedValue = cast(uint)_value;
135 		_ubytes[_offset++] = cast(ubyte)(unsignedValue >> 0);
136 		_ubytes[_offset++] = cast(ubyte)(unsignedValue >> 8);
137 		_ubytes[_offset++] = cast(ubyte)(unsignedValue >> 16);
138 		_ubytes[_offset] = cast(ubyte)(unsignedValue >> 24);
139 	}
140 }
141 unittest
142 {
143     import std.algorithm:equal;
144 
145     enum ubyte[] sourceData = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
146     ubyte[] data = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
147     
148     auto crypto = XTEA([1,2,3,4], 64);
149 
150     crypto.Encrypt(data);
151     crypto.Decrypt(data);
152     assert(equal(sourceData,data));
153 }