1 module threefish512; 2 3 // memcpy 4 extern(C) nothrow @nogc void* memcpy(void* dst, const void* src, size_t n); 5 6 class Threefish512 7 { 8 private { 9 // Размер блока шифра 10 enum blockSize = 64; 11 // Количество 64-битных слов в ключе (и в блоке) 12 enum Nw = 8; 13 // Количество раундов 14 enum Nr = 72; 15 // Количество раундов (за вычетом последнего) 16 enum Ns = Nr / 4; 17 // Функция перестановки 18 uint[8] p = [2, 1, 4, 7, 6, 5, 0, 3]; 19 uint[8] p_1 = [6, 1, 0, 7, 2, 5, 4, 3]; 20 21 // Функция смешивания и перестановки 22 uint[4][8] r = [ 23 [46, 36, 19, 37], 24 [33, 27, 14, 42], 25 [17, 49, 36, 39], 26 [44, 9 , 54, 56], 27 [39, 30, 34, 24], 28 [13, 50, 10, 17], 29 [25, 29, 39, 43], 30 [8 , 35, 56, 22] 31 ]; 32 33 // Твик-значение (свободный параметр алгоритма) 34 ulong[3] t; 35 // Раундовые ключи 36 ulong[8][Ns + 1] subKeys; 37 38 auto _mix(ref ulong[2] x, ulong r, ref ulong[2] y) 39 { 40 y[0] = x[0] + x[1]; 41 y[1] = (x[1] << r) | (x[1] >> (64 - r)); 42 y[1] ^= y[0]; 43 } 44 45 auto _demix(ref ulong[2] y, ulong r, ref ulong[2] x) 46 { 47 y[1] ^= y[0]; 48 x[1] = (y[1] << (64 - r)) | (y[1] >> r); 49 x[0] = y[0] - x[1]; 50 } 51 52 alias _mod8 = (ulong a) => a & 7UL; 53 } 54 55 /// Шифрование блока 56 /// plain - указатель на блок для шифрования, c - массив-приемник результата 57 void crypt(ulong* plainData, ulong* c) @system 58 { 59 ulong[8] f; 60 ulong[8] e; 61 ulong[2] y; 62 ulong[2] x; 63 ulong[8] v; 64 uint i; 65 66 memcpy (&v[0], plainData, 64); 67 68 for (uint round = 0; round < Nr; round++) 69 { 70 if (round % 4 == 0) 71 { 72 uint s = round >> 2; 73 74 for (i = 0; i < Nw; i++) 75 { 76 e[i] = v[i] + subKeys[s][i]; 77 } 78 } 79 else 80 { 81 for (i = 0; i < Nw; i++) 82 { 83 e[i] = v[i]; 84 } 85 } 86 87 for (i = 0; i < Nw / 2; i++) 88 { 89 x[0] = e[i * 2]; 90 x[1] = e[i * 2 + 1]; 91 92 _mix(x, r[_mod8(round)][i], y); 93 94 f[i * 2] = y[0]; 95 f[i * 2 + 1] = y[1]; 96 } 97 98 for (i = 0; i < Nw; i++) 99 { 100 v[i] = f[p[i]]; 101 } 102 } 103 104 for (i = 0; i < Nw; i++) 105 { 106 c[i] = v[i] + subKeys[Ns][i]; 107 } 108 } 109 110 /// Шифрование блока (безопасная версия) 111 /// plain - массив с данными блока 112 auto crypt(ulong[8] plainData) 113 { 114 ulong[8] c = 0; 115 crypt(plainData.ptr, c.ptr); 116 return c; 117 } 118 119 /// Дешифрование блока 120 /// plain - указатель на блок для дешифрования, c - массив-приемник результата 121 void decrypt(ulong* plainData, ulong* c) @system 122 { 123 ulong[8] f; 124 ulong[8] e; 125 ulong[2] y; 126 ulong[2] x; 127 ulong[8] v; 128 uint i; 129 130 memcpy(&v[0], plainData, 64); 131 132 for (uint round = Nr; round > 0; round--) 133 { 134 if (round % 4 == 0) 135 { 136 uint s = round >> 2; 137 for (i = 0; i < Nw; i++) 138 { 139 f[i] = v[i] - subKeys[s][i]; 140 } 141 } 142 else 143 { 144 for (i = 0; i < Nw; i++) 145 { 146 f[i] = v[i]; 147 } 148 } 149 150 for (i = 0; i < Nw; i++) 151 { 152 e[i] = f[p_1[i]]; 153 } 154 155 for (i = 0; i < Nw / 2; i++) 156 { 157 y[0] = e[i * 2]; 158 y[1] = e[i * 2 + 1]; 159 160 _demix(y, r[_mod8(round - 1)][i], x); 161 162 v[i * 2] = x[0]; 163 v[i * 2 + 1] = x[1]; 164 } 165 } 166 167 for (i = 0; i < Nw; i++) 168 { 169 c[i] = v[i] - subKeys[0][i]; 170 } 171 } 172 173 /// Дешифрование блока (безопасная версия) 174 /// plain - массив с данными блока 175 auto decrypt(ulong[8] plain) 176 { 177 ulong[8] c = 0; 178 decrypt(plain.ptr, c.ptr); 179 return c; 180 } 181 182 /// Подготовка раундовых ключей 183 /// keyData - указатель на массив с ключом, tweakData - указатель на массив с твик-значением 184 void setup(ulong* keyData, ulong* tweakData) @system 185 { 186 uint i; 187 ulong[8] K; 188 ulong[2] T; 189 ulong[9] key; 190 191 // C240 constant 192 ulong kNw = 0x1BD11BDAA9FC1A22; 193 194 memcpy(&K[0], &keyData[0], 64); 195 memcpy(&T[0], &tweakData[0], 16); 196 197 for (i = 0; i < Nw; i++) 198 { 199 kNw ^= K[i]; 200 key[i] = K[i]; 201 } 202 203 key[8] = kNw; 204 205 t[0] = T[0]; 206 t[1] = T[1]; 207 t[2] = T[0] ^ T[1]; 208 209 for (uint round = 0; round <= Ns; round++) 210 { 211 for (i = 0; i < Nw; i++) 212 { 213 subKeys[round][i] = key[(round + i) % (Nw + 1)]; 214 215 if (i == Nw - 3) 216 { 217 subKeys[round][i] += t[round % 3]; 218 } 219 else if (i == Nw - 2) 220 { 221 subKeys[round][i] += t[(round + 1) % 3]; 222 } 223 else if (i == Nw - 1) 224 { 225 subKeys[round][i] += round; 226 } 227 } 228 } 229 } 230 231 /// Подготовка раундовых ключей (безопасная версия) 232 /// keyData - указатель на массив с ключом, tweakData - указатель на массив с твик-значением 233 void setup(ulong[8] keyData, ulong[2] tweakData) 234 { 235 setup(keyData.ptr, tweakData.ptr); 236 } 237 }