Coverage Report

Created: 2026-02-07 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/block/twofish/twofish.cpp
Line
Count
Source
1
/*
2
* Twofish
3
* (C) 1999-2007,2017 Jack Lloyd
4
*
5
* The key schedule implementation is based on a public domain
6
* implementation by Matthew Skala
7
*
8
* Botan is released under the Simplified BSD License (see license.txt)
9
*/
10
11
#include <botan/internal/twofish.h>
12
13
#include <botan/internal/loadstor.h>
14
#include <botan/internal/rotate.h>
15
16
namespace Botan {
17
18
namespace {
19
20
inline void TF_E(
21
0
   uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, uint32_t RK1, uint32_t RK2, const secure_vector<uint32_t>& SB) {
22
0
   uint32_t X = SB[get_byte<3>(A)] ^ SB[256 + get_byte<2>(A)] ^ SB[512 + get_byte<1>(A)] ^ SB[768 + get_byte<0>(A)];
23
0
   uint32_t Y = SB[get_byte<0>(B)] ^ SB[256 + get_byte<3>(B)] ^ SB[512 + get_byte<2>(B)] ^ SB[768 + get_byte<1>(B)];
24
25
0
   X += Y;
26
0
   Y += X;
27
28
0
   X += RK1;
29
0
   Y += RK2;
30
31
0
   C = rotr<1>(C ^ X);
32
0
   D = rotl<1>(D) ^ Y;
33
0
}
34
35
inline void TF_D(
36
0
   uint32_t A, uint32_t B, uint32_t& C, uint32_t& D, uint32_t RK1, uint32_t RK2, const secure_vector<uint32_t>& SB) {
37
0
   uint32_t X = SB[get_byte<3>(A)] ^ SB[256 + get_byte<2>(A)] ^ SB[512 + get_byte<1>(A)] ^ SB[768 + get_byte<0>(A)];
38
0
   uint32_t Y = SB[get_byte<0>(B)] ^ SB[256 + get_byte<3>(B)] ^ SB[512 + get_byte<2>(B)] ^ SB[768 + get_byte<1>(B)];
39
40
0
   X += Y;
41
0
   Y += X;
42
43
0
   X += RK1;
44
0
   Y += RK2;
45
46
0
   C = rotl<1>(C) ^ X;
47
0
   D = rotr<1>(D ^ Y);
48
0
}
49
50
}  // namespace
51
52
/*
53
* Twofish Encryption
54
*/
55
0
void Twofish::encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
56
0
   assert_key_material_set();
57
58
0
   while(blocks >= 2) {
59
0
      uint32_t A0 = 0;
60
0
      uint32_t B0 = 0;
61
0
      uint32_t C0 = 0;
62
0
      uint32_t D0 = 0;
63
0
      uint32_t A1 = 0;
64
0
      uint32_t B1 = 0;
65
0
      uint32_t C1 = 0;
66
0
      uint32_t D1 = 0;
67
0
      load_le(in, A0, B0, C0, D0, A1, B1, C1, D1);
68
69
0
      A0 ^= m_RK[0];
70
0
      A1 ^= m_RK[0];
71
0
      B0 ^= m_RK[1];
72
0
      B1 ^= m_RK[1];
73
0
      C0 ^= m_RK[2];
74
0
      C1 ^= m_RK[2];
75
0
      D0 ^= m_RK[3];
76
0
      D1 ^= m_RK[3];
77
78
0
      for(size_t k = 8; k != 40; k += 4) {
79
0
         TF_E(A0, B0, C0, D0, m_RK[k + 0], m_RK[k + 1], m_SB);
80
0
         TF_E(A1, B1, C1, D1, m_RK[k + 0], m_RK[k + 1], m_SB);
81
82
0
         TF_E(C0, D0, A0, B0, m_RK[k + 2], m_RK[k + 3], m_SB);
83
0
         TF_E(C1, D1, A1, B1, m_RK[k + 2], m_RK[k + 3], m_SB);
84
0
      }
85
86
0
      C0 ^= m_RK[4];
87
0
      C1 ^= m_RK[4];
88
0
      D0 ^= m_RK[5];
89
0
      D1 ^= m_RK[5];
90
0
      A0 ^= m_RK[6];
91
0
      A1 ^= m_RK[6];
92
0
      B0 ^= m_RK[7];
93
0
      B1 ^= m_RK[7];
94
95
0
      store_le(out, C0, D0, A0, B0, C1, D1, A1, B1);
96
97
0
      blocks -= 2;
98
0
      out += 2 * BLOCK_SIZE;
99
0
      in += 2 * BLOCK_SIZE;
100
0
   }
101
102
0
   if(blocks > 0) {
103
0
      uint32_t A = 0;
104
0
      uint32_t B = 0;
105
0
      uint32_t C = 0;
106
0
      uint32_t D = 0;
107
0
      load_le(in, A, B, C, D);
108
109
0
      A ^= m_RK[0];
110
0
      B ^= m_RK[1];
111
0
      C ^= m_RK[2];
112
0
      D ^= m_RK[3];
113
114
0
      for(size_t k = 8; k != 40; k += 4) {
115
0
         TF_E(A, B, C, D, m_RK[k], m_RK[k + 1], m_SB);
116
0
         TF_E(C, D, A, B, m_RK[k + 2], m_RK[k + 3], m_SB);
117
0
      }
118
119
0
      C ^= m_RK[4];
120
0
      D ^= m_RK[5];
121
0
      A ^= m_RK[6];
122
0
      B ^= m_RK[7];
123
124
0
      store_le(out, C, D, A, B);
125
0
   }
126
0
}
127
128
/*
129
* Twofish Decryption
130
*/
131
0
void Twofish::decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const {
132
0
   assert_key_material_set();
133
134
0
   while(blocks >= 2) {
135
0
      uint32_t A0 = 0;
136
0
      uint32_t B0 = 0;
137
0
      uint32_t C0 = 0;
138
0
      uint32_t D0 = 0;
139
0
      uint32_t A1 = 0;
140
0
      uint32_t B1 = 0;
141
0
      uint32_t C1 = 0;
142
0
      uint32_t D1 = 0;
143
0
      load_le(in, A0, B0, C0, D0, A1, B1, C1, D1);
144
145
0
      A0 ^= m_RK[4];
146
0
      A1 ^= m_RK[4];
147
0
      B0 ^= m_RK[5];
148
0
      B1 ^= m_RK[5];
149
0
      C0 ^= m_RK[6];
150
0
      C1 ^= m_RK[6];
151
0
      D0 ^= m_RK[7];
152
0
      D1 ^= m_RK[7];
153
154
0
      for(size_t k = 40; k != 8; k -= 4) {
155
0
         TF_D(A0, B0, C0, D0, m_RK[k - 2], m_RK[k - 1], m_SB);
156
0
         TF_D(A1, B1, C1, D1, m_RK[k - 2], m_RK[k - 1], m_SB);
157
158
0
         TF_D(C0, D0, A0, B0, m_RK[k - 4], m_RK[k - 3], m_SB);
159
0
         TF_D(C1, D1, A1, B1, m_RK[k - 4], m_RK[k - 3], m_SB);
160
0
      }
161
162
0
      C0 ^= m_RK[0];
163
0
      C1 ^= m_RK[0];
164
0
      D0 ^= m_RK[1];
165
0
      D1 ^= m_RK[1];
166
0
      A0 ^= m_RK[2];
167
0
      A1 ^= m_RK[2];
168
0
      B0 ^= m_RK[3];
169
0
      B1 ^= m_RK[3];
170
171
0
      store_le(out, C0, D0, A0, B0, C1, D1, A1, B1);
172
173
0
      blocks -= 2;
174
0
      out += 2 * BLOCK_SIZE;
175
0
      in += 2 * BLOCK_SIZE;
176
0
   }
177
178
0
   if(blocks > 0) {
179
0
      uint32_t A = 0;
180
0
      uint32_t B = 0;
181
0
      uint32_t C = 0;
182
0
      uint32_t D = 0;
183
0
      load_le(in, A, B, C, D);
184
185
0
      A ^= m_RK[4];
186
0
      B ^= m_RK[5];
187
0
      C ^= m_RK[6];
188
0
      D ^= m_RK[7];
189
190
0
      for(size_t k = 40; k != 8; k -= 4) {
191
0
         TF_D(A, B, C, D, m_RK[k - 2], m_RK[k - 1], m_SB);
192
0
         TF_D(C, D, A, B, m_RK[k - 4], m_RK[k - 3], m_SB);
193
0
      }
194
195
0
      C ^= m_RK[0];
196
0
      D ^= m_RK[1];
197
0
      A ^= m_RK[2];
198
0
      B ^= m_RK[3];
199
200
0
      store_le(out, C, D, A, B);
201
0
   }
202
0
}
203
204
0
bool Twofish::has_keying_material() const {
205
0
   return !m_SB.empty();
206
0
}
207
208
/*
209
* Twofish Key Schedule
210
*/
211
0
void Twofish::key_schedule(std::span<const uint8_t> key) {
212
0
   m_SB.resize(1024);
213
0
   m_RK.resize(40);
214
215
0
   secure_vector<uint8_t> S(16);
216
217
0
   for(size_t i = 0; i != key.size(); ++i) {
218
      /*
219
      * Do one column of the RS matrix multiplication
220
      */
221
0
      if(key[i] != 0) {
222
0
         const uint8_t X = POLY_TO_EXP[key[i] - 1];
223
224
0
         const uint8_t RS1 = RS[(4 * i) % 32];
225
0
         const uint8_t RS2 = RS[(4 * i + 1) % 32];
226
0
         const uint8_t RS3 = RS[(4 * i + 2) % 32];
227
0
         const uint8_t RS4 = RS[(4 * i + 3) % 32];
228
229
0
         S[4 * (i / 8)] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255];
230
0
         S[4 * (i / 8) + 1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255];
231
0
         S[4 * (i / 8) + 2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255];
232
0
         S[4 * (i / 8) + 3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255];
233
0
      }
234
0
   }
235
236
0
   if(key.size() == 16) {
237
0
      for(size_t i = 0; i != 256; ++i) {
238
0
         m_SB[i] = MDS0[Q0[Q0[i] ^ S[0]] ^ S[4]];
239
0
         m_SB[256 + i] = MDS1[Q0[Q1[i] ^ S[1]] ^ S[5]];
240
0
         m_SB[512 + i] = MDS2[Q1[Q0[i] ^ S[2]] ^ S[6]];
241
0
         m_SB[768 + i] = MDS3[Q1[Q1[i] ^ S[3]] ^ S[7]];
242
0
      }
243
244
0
      for(size_t i = 0; i < 40; i += 2) {
245
0
         uint32_t X = MDS0[Q0[Q0[i] ^ key[8]] ^ key[0]] ^ MDS1[Q0[Q1[i] ^ key[9]] ^ key[1]] ^
246
0
                      MDS2[Q1[Q0[i] ^ key[10]] ^ key[2]] ^ MDS3[Q1[Q1[i] ^ key[11]] ^ key[3]];
247
0
         uint32_t Y = MDS0[Q0[Q0[i + 1] ^ key[12]] ^ key[4]] ^ MDS1[Q0[Q1[i + 1] ^ key[13]] ^ key[5]] ^
248
0
                      MDS2[Q1[Q0[i + 1] ^ key[14]] ^ key[6]] ^ MDS3[Q1[Q1[i + 1] ^ key[15]] ^ key[7]];
249
0
         Y = rotl<8>(Y);
250
0
         X += Y;
251
0
         Y += X;
252
253
0
         m_RK[i] = X;
254
0
         m_RK[i + 1] = rotl<9>(Y);
255
0
      }
256
0
   } else if(key.size() == 24) {
257
0
      for(size_t i = 0; i != 256; ++i) {
258
0
         m_SB[i] = MDS0[Q0[Q0[Q1[i] ^ S[0]] ^ S[4]] ^ S[8]];
259
0
         m_SB[256 + i] = MDS1[Q0[Q1[Q1[i] ^ S[1]] ^ S[5]] ^ S[9]];
260
0
         m_SB[512 + i] = MDS2[Q1[Q0[Q0[i] ^ S[2]] ^ S[6]] ^ S[10]];
261
0
         m_SB[768 + i] = MDS3[Q1[Q1[Q0[i] ^ S[3]] ^ S[7]] ^ S[11]];
262
0
      }
263
264
0
      for(size_t i = 0; i < 40; i += 2) {
265
0
         uint32_t X =
266
0
            MDS0[Q0[Q0[Q1[i] ^ key[16]] ^ key[8]] ^ key[0]] ^ MDS1[Q0[Q1[Q1[i] ^ key[17]] ^ key[9]] ^ key[1]] ^
267
0
            MDS2[Q1[Q0[Q0[i] ^ key[18]] ^ key[10]] ^ key[2]] ^ MDS3[Q1[Q1[Q0[i] ^ key[19]] ^ key[11]] ^ key[3]];
268
0
         uint32_t Y = MDS0[Q0[Q0[Q1[i + 1] ^ key[20]] ^ key[12]] ^ key[4]] ^
269
0
                      MDS1[Q0[Q1[Q1[i + 1] ^ key[21]] ^ key[13]] ^ key[5]] ^
270
0
                      MDS2[Q1[Q0[Q0[i + 1] ^ key[22]] ^ key[14]] ^ key[6]] ^
271
0
                      MDS3[Q1[Q1[Q0[i + 1] ^ key[23]] ^ key[15]] ^ key[7]];
272
0
         Y = rotl<8>(Y);
273
0
         X += Y;
274
0
         Y += X;
275
276
0
         m_RK[i] = X;
277
0
         m_RK[i + 1] = rotl<9>(Y);
278
0
      }
279
0
   } else if(key.size() == 32) {
280
0
      for(size_t i = 0; i != 256; ++i) {
281
0
         m_SB[i] = MDS0[Q0[Q0[Q1[Q1[i] ^ S[0]] ^ S[4]] ^ S[8]] ^ S[12]];
282
0
         m_SB[256 + i] = MDS1[Q0[Q1[Q1[Q0[i] ^ S[1]] ^ S[5]] ^ S[9]] ^ S[13]];
283
0
         m_SB[512 + i] = MDS2[Q1[Q0[Q0[Q0[i] ^ S[2]] ^ S[6]] ^ S[10]] ^ S[14]];
284
0
         m_SB[768 + i] = MDS3[Q1[Q1[Q0[Q1[i] ^ S[3]] ^ S[7]] ^ S[11]] ^ S[15]];
285
0
      }
286
287
0
      for(size_t i = 0; i < 40; i += 2) {
288
0
         uint32_t X = MDS0[Q0[Q0[Q1[Q1[i] ^ key[24]] ^ key[16]] ^ key[8]] ^ key[0]] ^
289
0
                      MDS1[Q0[Q1[Q1[Q0[i] ^ key[25]] ^ key[17]] ^ key[9]] ^ key[1]] ^
290
0
                      MDS2[Q1[Q0[Q0[Q0[i] ^ key[26]] ^ key[18]] ^ key[10]] ^ key[2]] ^
291
0
                      MDS3[Q1[Q1[Q0[Q1[i] ^ key[27]] ^ key[19]] ^ key[11]] ^ key[3]];
292
0
         uint32_t Y = MDS0[Q0[Q0[Q1[Q1[i + 1] ^ key[28]] ^ key[20]] ^ key[12]] ^ key[4]] ^
293
0
                      MDS1[Q0[Q1[Q1[Q0[i + 1] ^ key[29]] ^ key[21]] ^ key[13]] ^ key[5]] ^
294
0
                      MDS2[Q1[Q0[Q0[Q0[i + 1] ^ key[30]] ^ key[22]] ^ key[14]] ^ key[6]] ^
295
0
                      MDS3[Q1[Q1[Q0[Q1[i + 1] ^ key[31]] ^ key[23]] ^ key[15]] ^ key[7]];
296
0
         Y = rotl<8>(Y);
297
0
         X += Y;
298
0
         Y += X;
299
300
0
         m_RK[i] = X;
301
0
         m_RK[i + 1] = rotl<9>(Y);
302
0
      }
303
0
   }
304
0
}
305
306
/*
307
* Clear memory of sensitive data
308
*/
309
0
void Twofish::clear() {
310
0
   zap(m_SB);
311
0
   zap(m_RK);
312
0
}
313
314
}  // namespace Botan