1 /** 2 * Threefish 3 * 4 * Copyright: 5 * (C) 2013,2014 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.block.threefish; 12 13 import botan.constants; 14 static if (BOTAN_HAS_THREEFISH_512): 15 16 import botan.utils.rotate; 17 import botan.utils.loadstor; 18 import botan.block.block_cipher; 19 import botan.utils.types; 20 import botan.utils.mem_ops; 21 import std.format : format; 22 23 /** 24 * Threefish-512 25 */ 26 class Threefish512 : BlockCipherFixedParams!(64, 64), BlockCipher, SymmetricAlgorithm 27 { 28 public: 29 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 30 { 31 assert(m_K.length == 9, "Key was set"); 32 assert(m_T.length == 3, "Tweak was set"); 33 34 foreach (size_t i; 0 .. blocks) 35 { 36 ulong X0 = loadLittleEndian!ulong(input, 0); 37 ulong X1 = loadLittleEndian!ulong(input, 1); 38 ulong X2 = loadLittleEndian!ulong(input, 2); 39 ulong X3 = loadLittleEndian!ulong(input, 3); 40 ulong X4 = loadLittleEndian!ulong(input, 4); 41 ulong X5 = loadLittleEndian!ulong(input, 5); 42 ulong X6 = loadLittleEndian!ulong(input, 6); 43 ulong X7 = loadLittleEndian!ulong(input, 7); 44 45 mixin(THREEFISH_ENC_INJECT_KEY!(0)); 46 47 mixin(THREEFISH_ENC_8_ROUNDS!(1,2)); 48 mixin(THREEFISH_ENC_8_ROUNDS!(3,4)); 49 mixin(THREEFISH_ENC_8_ROUNDS!(5,6)); 50 mixin(THREEFISH_ENC_8_ROUNDS!(7,8)); 51 mixin(THREEFISH_ENC_8_ROUNDS!(9,10)); 52 mixin(THREEFISH_ENC_8_ROUNDS!(11,12)); 53 mixin(THREEFISH_ENC_8_ROUNDS!(13,14)); 54 mixin(THREEFISH_ENC_8_ROUNDS!(15,16)); 55 mixin(THREEFISH_ENC_8_ROUNDS!(17,18)); 56 57 storeLittleEndian(output, X0, X1, X2, X3, X4, X5, X6, X7); 58 59 input += 64; 60 output += 64; 61 } 62 } 63 64 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 65 { 66 assert(m_K.length == 9, "Key was set"); 67 assert(m_T.length == 3, "Tweak was set"); 68 69 foreach (size_t i; 0 .. blocks) 70 { 71 ulong X0 = loadLittleEndian!ulong(input, 0); 72 ulong X1 = loadLittleEndian!ulong(input, 1); 73 ulong X2 = loadLittleEndian!ulong(input, 2); 74 ulong X3 = loadLittleEndian!ulong(input, 3); 75 ulong X4 = loadLittleEndian!ulong(input, 4); 76 ulong X5 = loadLittleEndian!ulong(input, 5); 77 ulong X6 = loadLittleEndian!ulong(input, 6); 78 ulong X7 = loadLittleEndian!ulong(input, 7); 79 80 mixin(THREEFISH_DEC_INJECT_KEY!(18)); 81 82 mixin(THREEFISH_DEC_8_ROUNDS!(17,16)); 83 mixin(THREEFISH_DEC_8_ROUNDS!(15,14)); 84 mixin(THREEFISH_DEC_8_ROUNDS!(13,12)); 85 mixin(THREEFISH_DEC_8_ROUNDS!(11,10)); 86 mixin(THREEFISH_DEC_8_ROUNDS!(9,8)); 87 mixin(THREEFISH_DEC_8_ROUNDS!(7,6)); 88 mixin(THREEFISH_DEC_8_ROUNDS!(5,4)); 89 mixin(THREEFISH_DEC_8_ROUNDS!(3,2)); 90 mixin(THREEFISH_DEC_8_ROUNDS!(1,0)); 91 92 storeLittleEndian(output, X0, X1, X2, X3, X4, X5, X6, X7); 93 94 input += 64; 95 output += 64; 96 } 97 } 98 99 final void setTweak(const(ubyte)* tweak, size_t len) 100 { 101 if (len != 16) 102 throw new Exception("Unsupported twofish tweak length"); 103 m_T[0] = loadLittleEndian!ulong(tweak, 0); 104 m_T[1] = loadLittleEndian!ulong(tweak, 1); 105 m_T[2] = m_T[0] ^ m_T[1]; 106 } 107 108 override void clear() 109 { 110 if (m_T.length == 0) m_T = SecureVector!ulong(3); 111 else zeroise(m_T); 112 if (m_K.length == 0) m_K = SecureVector!ulong(9); 113 else zeroise(m_K); 114 } 115 116 final override @property string name() const { return "Threefish-512"; } 117 override @property size_t parallelism() const { return 1; } 118 override BlockCipher clone() const { return new Threefish512; } 119 override size_t blockSize() const { return super.blockSize(); } 120 override KeyLengthSpecification keySpec() const { return super.keySpec(); } 121 122 this() { 123 m_T = SecureVector!ulong(3); 124 } 125 126 protected: 127 final ref const(SecureVector!ulong) getT() const { return m_T; } 128 final ref const(SecureVector!ulong) getK() const { return m_K; } 129 override void keySchedule(const(ubyte)* key, size_t) 130 { 131 // todo: define key schedule for smaller keys 132 m_K.resize(9); 133 134 foreach (size_t i; 0 .. 8) 135 m_K[i] = loadLittleEndian!ulong(key, i); 136 137 m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ 138 m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; 139 } 140 public: 141 final void skeinFeedfwd(const ref SecureVector!ulong M, const ref SecureVector!ulong T) 142 { 143 assert(m_K.length == 9, "Key was set"); 144 assert(M.length == 8, "Single block"); 145 146 m_T[0] = T[0]; 147 m_T[1] = T[1]; 148 m_T[2] = T[0] ^ T[1]; 149 150 ulong X0 = M[0]; 151 ulong X1 = M[1]; 152 ulong X2 = M[2]; 153 ulong X3 = M[3]; 154 ulong X4 = M[4]; 155 ulong X5 = M[5]; 156 ulong X6 = M[6]; 157 ulong X7 = M[7]; 158 159 mixin(THREEFISH_ENC_INJECT_KEY!(0)); 160 161 mixin(THREEFISH_ENC_8_ROUNDS!(1,2)); 162 mixin(THREEFISH_ENC_8_ROUNDS!(3,4)); 163 mixin(THREEFISH_ENC_8_ROUNDS!(5,6)); 164 mixin(THREEFISH_ENC_8_ROUNDS!(7,8)); 165 mixin(THREEFISH_ENC_8_ROUNDS!(9,10)); 166 mixin(THREEFISH_ENC_8_ROUNDS!(11,12)); 167 mixin(THREEFISH_ENC_8_ROUNDS!(13,14)); 168 mixin(THREEFISH_ENC_8_ROUNDS!(15,16)); 169 mixin(THREEFISH_ENC_8_ROUNDS!(17,18)); 170 171 m_K[0] = M[0] ^ X0; 172 m_K[1] = M[1] ^ X1; 173 m_K[2] = M[2] ^ X2; 174 m_K[3] = M[3] ^ X3; 175 m_K[4] = M[4] ^ X4; 176 m_K[5] = M[5] ^ X5; 177 m_K[6] = M[6] ^ X6; 178 m_K[7] = M[7] ^ X7; 179 180 m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ 181 m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; 182 } 183 184 // Private data 185 SecureVector!ulong m_T; 186 SecureVector!ulong m_K; 187 } 188 189 package: 190 191 192 enum string THREEFISH_ENC_ROUND(alias _X0, alias _X1, alias _X2, alias _X3, 193 alias _X4, alias _X5, alias _X6, alias _X7, 194 ubyte _ROT1, ubyte _ROT2, ubyte _ROT3, ubyte _ROT4) = q{ 195 %1$s += %5$s; 196 %2$s += %6$s; 197 %3$s += %7$s; 198 %4$s += %8$s; 199 %5$s = rotateLeft(%5$s, %9$s); 200 %6$s = rotateLeft(%6$s, %10$s); 201 %7$s = rotateLeft(%7$s, %11$s); 202 %8$s = rotateLeft(%8$s, %12$s); 203 %5$s ^= %1$s; 204 %6$s ^= %2$s; 205 %7$s ^= %3$s; 206 %8$s ^= %4$s; 207 }.format( 208 __traits(identifier, _X0), __traits(identifier, _X1), __traits(identifier, _X2), __traits(identifier, _X3), 209 __traits(identifier, _X4), __traits(identifier, _X5), __traits(identifier, _X6), __traits(identifier, _X7), 210 _ROT1.stringof, _ROT2.stringof, _ROT3.stringof, _ROT4.stringof); 211 212 enum string THREEFISH_ENC_INJECT_KEY(ushort r) = 213 `X0 += m_K[(` ~ r.stringof ~ ` ) % 9]; 214 X1 += m_K[(` ~ (r + 1).stringof ~ `) % 9]; 215 X2 += m_K[(` ~ (r + 2).stringof ~ `) % 9]; 216 X3 += m_K[(` ~ (r + 3).stringof ~ `) % 9]; 217 X4 += m_K[(` ~ (r + 4).stringof ~ `) % 9]; 218 X5 += m_K[(` ~ (r + 5).stringof ~ `) % 9] + m_T[(` ~ r.stringof ~ ` ) % 3]; 219 X6 += m_K[(` ~ (r + 6).stringof ~ `) % 9] + m_T[(` ~ (r + 1).stringof ~ `) % 3]; 220 X7 += m_K[(` ~ (r + 7).stringof ~ `) % 9] + (` ~ r.stringof ~ `);`; 221 222 enum string THREEFISH_ENC_8_ROUNDS(ushort R1, ushort R2) = 223 `mixin(THREEFISH_ENC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37)); 224 mixin(THREEFISH_ENC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42)); 225 mixin(THREEFISH_ENC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39)); 226 mixin(THREEFISH_ENC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56)); 227 mixin(THREEFISH_ENC_INJECT_KEY!(` ~ R1.stringof ~ `)); 228 mixin(THREEFISH_ENC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24)); 229 mixin(THREEFISH_ENC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17)); 230 mixin(THREEFISH_ENC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43)); 231 mixin(THREEFISH_ENC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22)); 232 mixin(THREEFISH_ENC_INJECT_KEY!(` ~ R2.stringof ~ `));`; 233 234 enum string THREEFISH_DEC_ROUND(alias _X0, alias _X1, alias _X2, alias _X3, 235 alias _X4, alias _X5, alias _X6, alias _X7, 236 ubyte _ROT1, ubyte _ROT2, ubyte _ROT3, ubyte _ROT4) = q{ 237 %5$s ^= %1$s; 238 %6$s ^= %2$s; 239 %7$s ^= %3$s; 240 %8$s ^= %4$s; 241 %5$s = rotateRight(%5$s, %9$s); 242 %6$s = rotateRight(%6$s, %10$s); 243 %7$s = rotateRight(%7$s, %11$s); 244 %8$s = rotateRight(%8$s, %12$s); 245 %1$s -= %5$s; 246 %2$s -= %6$s; 247 %3$s -= %7$s; 248 %4$s -= %8$s; 249 }.format( 250 __traits(identifier, _X0), __traits(identifier, _X1), __traits(identifier, _X2), __traits(identifier, _X3), 251 __traits(identifier, _X4), __traits(identifier, _X5), __traits(identifier, _X6), __traits(identifier, _X7), 252 _ROT1.stringof, _ROT2.stringof, _ROT3.stringof, _ROT4.stringof); 253 254 enum string THREEFISH_DEC_INJECT_KEY(ushort r) = 255 `X0 -= m_K[(` ~ r.stringof ~ ` ) % 9]; 256 X1 -= m_K[(` ~ (r+1).stringof ~ `) % 9]; 257 X2 -= m_K[(` ~ (r+2).stringof ~ `) % 9]; 258 X3 -= m_K[(` ~ (r+3).stringof ~ `) % 9]; 259 X4 -= m_K[(` ~ (r+4).stringof ~ `) % 9]; 260 X5 -= m_K[(` ~ (r+5).stringof ~ `) % 9] + m_T[(` ~ r.stringof ~ ` ) % 3]; 261 X6 -= m_K[(` ~ (r+6).stringof ~ `) % 9] + m_T[(` ~ (r+1).stringof ~ `) % 3]; 262 X7 -= m_K[(` ~ (r+7).stringof ~ `) % 9] + (` ~ r.stringof ~ `);`; 263 264 enum string THREEFISH_DEC_8_ROUNDS(ushort R1, ushort R2) = 265 `mixin(THREEFISH_DEC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3, 8,35,56,22)); 266 mixin(THREEFISH_DEC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 25,29,39,43)); 267 mixin(THREEFISH_DEC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 13,50,10,17)); 268 mixin(THREEFISH_DEC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 39,30,34,24)); 269 mixin(THREEFISH_DEC_INJECT_KEY!(` ~ R1.stringof ~ `)); 270 mixin(THREEFISH_DEC_ROUND!(X6,X0,X2,X4, X1,X7,X5,X3, 44, 9,54,56)); 271 mixin(THREEFISH_DEC_ROUND!(X4,X6,X0,X2, X1,X3,X5,X7, 17,49,36,39)); 272 mixin(THREEFISH_DEC_ROUND!(X2,X4,X6,X0, X1,X7,X5,X3, 33,27,14,42)); 273 mixin(THREEFISH_DEC_ROUND!(X0,X2,X4,X6, X1,X3,X5,X7, 46,36,19,37)); 274 mixin(THREEFISH_DEC_INJECT_KEY!(` ~ R2.stringof ~ `));`; 275