1 /// Implementation of TEA digesters.
2 module tern.digest.tea;
3 
4 import tern.digest;
5 import tern.algorithm;
6 import tern.serialization;
7 
8 /**
9  * Implementation of Tiny Encryption Algorithm (TEA) digester.
10  *
11  * TEA is a symmetric block cipher with a block size of 64 bits and a key size of 128 bits.
12  * It operates on 64-bit blocks using a Feistel network structure. TEA is designed to be fast
13  * and simple, yet difficult to cryptanalyze.
14  *
15  * Example:
16  * ```d
17  * import tern.digest.tea;
18  * 
19  * ubyte[] data = [1, 2, 3, 4, 5];
20  * string key = "my_secret_key";
21  * TEA.encrypt(data, key);
22  * ```
23  */
24 public static @digester class TEA
25 {
26 public:
27 static:
28 pure:
29     /**
30      * Encrypts the given byte array `data` using TEA algorithm.
31      *
32      * Params:
33      *  data = Reference to the input byte array to be encrypted.
34      *  key = The encryption key. Must be 128 bits (16 characters).
35      */
36     void encrypt(ref ubyte[] data, string key) 
37     {
38         assert(key.length == 16, "Key must be 128 bits!");
39 
40         uint[4] k = *cast(uint[4]*)key.ptr;
41         uint delta = 0x9E3779B9;
42         uint rounds = 32;
43         uint sum = 0;
44         uint k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
45 
46         vacpp(data, 8);
47         
48         for (size_t i = 0; i < data.length; i += 8) 
49         {
50             auto block = data[i .. i + 8].ptr;
51             uint v0 = *cast(uint*)block;
52             uint v1 = *cast(uint*)(block + 4);
53             sum = 0;
54 
55             for (uint j = 0; j < rounds; ++j) 
56             {
57                 sum += delta;
58                 v0 += (((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1));
59                 v1 += (((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3));
60             }
61 
62      *cast(uint*)block = v0;
63      *cast(uint*)(block + 4) = v1;
64         }
65     }
66 
67     /**
68      * Decrypts the given byte array `data` using TEA algorithm.
69      *
70      * Params:
71      *  data = Reference to the input byte array to be decrypted.
72      *  key = The decryption key. Must be 128 bits (16 characters).
73      */
74     void decrypt(ref ubyte[] data, string key) 
75     {
76         assert(key.length == 16, "Key must be 128 bits!");
77 
78         uint[4] k = *cast(uint[4]*)key.ptr;
79         uint delta = 0x9E3779B9;
80         uint rounds = 32;
81         uint sum;
82         uint k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
83 
84         if (data.length % 8 != 0)
85             vacpp(data, 8);
86 
87         for (size_t i = 0; i < data.length; i += 8) 
88         {
89             auto block = data[i .. i + 8].ptr;
90             uint v0 = *cast(uint*)block;
91             uint v1 = *cast(uint*)(block + 4);
92             sum = delta << 5;
93 
94             for (uint j = 0; j < rounds; ++j) 
95             {
96                 v1 -= (((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3));
97                 v0 -= (((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1));
98                 sum -= delta;
99             }
100 
101      *cast(uint*)block = v0;
102      *cast(uint*)(block + 4) = v1;
103         }
104 
105         unvacpp(data);
106     }
107 }
108 
109 /**
110  * Implementation of eXtended Tiny Encryption Algorithm (XTEA) digester.
111  *
112  * XTEA is an extension of TEA with a larger block size (64 bits) and a more complex key schedule.
113  * It offers higher security than TEA, making it suitable for applications requiring stronger encryption.
114  *
115  * Example:
116  * ```d
117  * import tern.digest.tea;
118  * 
119  * ubyte[] data = [1, 2, 3, 4, 5];
120  * string key = "my_secret_key";
121  * XTEA.encrypt(data, key);
122  * ```
123  */
124 public static @digester class XTEA 
125 {
126 public:
127 static:
128 pure:
129     /**
130      * Encrypts the given byte array `data` using XTEA algorithm.
131      *
132      * Params:
133      *  data = Reference to the input byte array to be encrypted.
134      *  key = The encryption key. Must be 128 bits (16 characters).
135      */
136     void encrypt(ref ubyte[] data, string key) 
137     {
138         assert(key.length == 16, "Key must be 128 bits!");
139 
140         int[4] k = *cast(int[4]*)key.ptr;
141         int delta = 0x9E3779B9;
142         int rounds = 32;
143         int sum = 0;
144 
145         vacpp(data, 8);
146 
147         for (size_t i = 0; i < data.length; i += 8) 
148         {
149             auto block = data[i .. i + 8].ptr;
150             int v0 = *cast(int*)block;
151             int v1 = *cast(int*)(block + 4);
152             sum = 0;
153 
154             for (int j = 0; j < rounds; ++j) 
155             {
156                 sum += delta;
157                 v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[(sum >> 11) & 3]);
158                 v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[sum & 3]);
159             }
160 
161         *cast(int*)block = v0;
162         *cast(int*)(block + 4) = v1;
163         }
164     }
165 
166     /**
167      * Decrypts the given byte array `data` using XTEA algorithm.
168      *
169      * Params:
170      *  data = Reference to the input byte array to be decrypted.
171      *  key = The decryption key. Must be 128 bits (16 characters).
172      */
173     void decrypt(ref ubyte[] data, string key) 
174     {
175         assert(key.length == 16, "Key must be 128 bits!");
176 
177         int[4] k = *cast(int[4]*)key.ptr;
178         int delta = 0x9E3779B9;
179         int rounds = 32;
180         int sum;
181 
182         if (data.length % 8 != 0)
183             vacpp(data, 8);
184 
185         for (size_t i = 0; i < data.length; i += 8) 
186         {
187             auto block = data[i .. i + 8].ptr;
188             int v0 = *cast(int*)block;
189             int v1 = *cast(int*)(block + 4);
190             sum = delta << 5;
191 
192             for (int j = 0; j < rounds; ++j) 
193             {
194                 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[sum & 3]);
195                 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[(sum >> 11) & 3]);
196                 sum -= delta;
197             }
198 
199             *cast(int*)block = v0;
200             *cast(int*)(block + 4) = v1;
201         }
202 
203         unvacpp(data);
204     }
205 }
206 
207 /**
208  * Implementation of XXTEA (Corrected Block TEA) digester.
209  *
210  * XXTEA is a corrected version of XTEA with a fixed block size of 64 bits and a simpler key schedule.
211  * It is designed to be more resistant against certain types of attacks compared to XTEA.
212  *
213  * Example:
214  * ```d
215  * import tern.digest.tea;
216  * 
217  * ubyte[] data = [1, 2, 3, 4, 5];
218  * string key = "my_secret_key";
219  * XXTEA.encrypt(data, key);
220  * ```
221  */
222 public static @digester class XXTEA 
223 {
224 public:
225 static:
226 pure:
227     /**
228      * Encrypts the given byte array `data` using XXTEA algorithm.
229      *
230      * Params:
231      *  data = Reference to the input byte array to be encrypted.
232      *  key = The encryption key. Must be 128 bits (16 characters).
233      */
234     void encrypt(ref ubyte[] data, string key) 
235     {
236         assert(key.length == 16, "Key must be 128 bits!");
237 
238         int[4] k = *cast(int[4]*)key.ptr;
239         int delta = 0x9E3779B9;
240         int rounds = 32;
241         int sum = 0;
242 
243         vacpp(data, 8);
244 
245         for (size_t i = 0; i < data.length; i += 8) 
246         {
247             auto block = data[i..(i + 8)].ptr;
248             int v0 = *cast(int*)block;
249             int v1 = *cast(int*)(block + 4);
250             sum = 0;
251 
252             for (int j = 0; j < rounds; ++j) 
253             {
254                 sum += delta;
255                 v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[(sum >> 11) & 3]);
256                 v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[sum & 3]);
257             }
258 
259             *cast(int*)block = v0;
260             *cast(int*)(block + 4) = v1;
261         }
262     }
263 
264     /**
265      * Decrypts the given byte array `data` using XXTEA algorithm.
266      *
267      * Params:
268      *  data = Reference to the input byte array to be decrypted.
269      *  key = The decryption key. Must be 128 bits (16 characters).
270      */
271     void decrypt(ref ubyte[] data, string key) 
272     {
273         assert(key.length == 16, "Key must be 128 bits!");
274 
275         int[4] k = *cast(int[4]*)key.ptr;
276         int delta = 0x9E3779B9;
277         int rounds = 32;
278         int sum;
279 
280         if (data.length % 8 != 0)
281             vacpp(data, 8);
282 
283         for (size_t i = 0; i < data.length; i += 8) 
284         {
285             auto block = data[i .. i + 8].ptr;
286             int v0 = *cast(int*)block;
287             int v1 = *cast(int*)(block + 4);
288             sum = delta << 5;
289 
290             for (int j = 0; j < rounds; ++j) 
291             {
292                 v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[sum & 3]);
293                 v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[(sum >> 11) & 3]);
294                 sum -= delta;
295             }
296 
297             *cast(int*)block = v0;
298             *cast(int*)(block + 4) = v1;
299         }
300 
301         unvacpp(data);
302     }
303 }