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