1 /// Implementation of HIGHT digester.
2 module tern.digest.hight;
3 
4 // TODO: Fix?
5 import tern.digest;
6 import tern.algorithm;
7 import tern.serialization;
8 
9 /**
10  * Implementation of HIGHT digester.
11  *
12  * HIGHT is a lightweight block cipher designed for low-resource environments.
13  * It operates by encrypting or decrypting data using a 128-bit key and 64-bit
14  * blocks.
15  *
16  * Example:
17  * ```d
18  * import tern.digest.hight;
19  * 
20  * ubyte[] data = [1, 2, 3, 4, 5, 6, 7, 8];
21  * string key = "1234567890123456";
22  * HIGHT.encrypt(data, key);
23  * ```
24  */
25 public static @digester class HIGHT
26 {
27 public:
28 static:
29 pure:
30     /**
31      * Encrypts the given data using the HIGHT algorithm with the specified key.
32      *
33      * Params:
34      *  data = Reference to the input byte array to be encrypted.
35      *  key = The key used for encryption. Must be 128 bits (16 bytes) long.
36      */
37     void encrypt(ref ubyte[] data, string key)
38     {
39         assert(key.length == 16, "Key must be 128 bits!");
40         vacpp(data, 8);
41 
42         ushort[16] roundKeys;
43         for (int i = 0; i < 16; i++)
44             roundKeys[i] = key[i] << 8 | key[i >= 15 ? 0 : i + 1];
45         
46         foreach (ref block; data.portionTo!(ubyte[8]))
47         {
48             ushort l = block[0] << 8 | block[1];
49             ushort r = block[2] << 8 | block[3];
50             ushort t;
51         
52             foreach (i; 0..16)
53             {
54                 r ^= ((l << 1) + (l >> 15) + roundKeys[i]) & 0xFFFF;
55                 t = l;
56                 l = r;
57                 r = t;
58             }
59         
60             t = l;
61             l = r;
62             r = t;
63         
64             block[0] = cast(ubyte)(l >> 8);
65             block[1] = cast(ubyte)(l & 0xFF);
66             block[2] = cast(ubyte)(r >> 8);
67             block[3] = cast(ubyte)(r & 0xFF);
68         }
69     }
70 
71     /**
72      * Decrypts the given data using the HIGHT algorithm with the specified key.
73      *
74      * Params:
75      *  data = Reference to the input byte array to be decrypted.
76      *  key = The key used for decryption. Must be 128 bits (16 bytes) long.
77      */
78     void decrypt(ref ubyte[] data, string key)
79     {
80         assert(key.length == 16, "Key must be 128 bits!");
81         if (data.length % 8 != 0)
82             vacpp(data, 8);
83 
84         ushort[16] roundKeys;
85         for (int i = 0; i < 16; i++)
86             roundKeys[i] = key[i] << 8 | key[i >= 15 ? 0 : i + 1];
87         
88         foreach (ref block; data.portionTo!(ubyte[8]))
89         {
90             ushort l = block[0] << 8 | block[1];
91             ushort r = block[2] << 8 | block[3];
92             ushort t;
93         
94             t = l;
95             l = r;
96             r = t;
97         
98             foreach_reverse (i; 0..16)
99             {
100                 t = r;
101                 r = l;
102                 l = t;
103                 r ^= ((l << 1) + (l >> 15) + roundKeys[i]) & 0xFFFF;
104             }
105         
106             block[0] = cast(ubyte)(l >> 8);
107             block[1] = cast(ubyte)(l & 0xFF);
108             block[2] = cast(ubyte)(r >> 8);
109             block[3] = cast(ubyte)(r & 0xFF);
110         }
111 
112         data = data[0..$-16];
113         unvacpp(data);
114     }
115 }