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