/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 |