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 }