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