Botan: src/filters/modes/xts/xts.cpp Source File

Botan 1.10.17

xts.cpp
Go to the documentation of this file.
1 /*
2 * XTS Mode
3 * (C) 2009 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7
8 #include <botan/xts.h>
9 #include <botan/internal/xor_buf.h>
10 #include <algorithm>
11 #include <stdexcept>
12
13 namespace Botan {
14
15 namespace {
16
17 void poly_double(byte tweak[], size_t size)
18 {
19 const byte polynomial = (size == 16) ? 0x87 : 0x1B;
20
21 byte carry = 0;
22 for(size_t i = 0; i != size; ++i)
23 {
24 byte carry2 = (tweak[i] >> 7);
25 tweak[i] = (tweak[i] << 1) | carry;
26 carry = carry2;
27 }
28
29 if(carry)
30 tweak[0] ^= polynomial;
31 }
32
33 /* XTS needs to process at least 2 blocks in parallel
34 because block_size+1 bytes are needed at the end
35 */
36 size_t xts_parallelism(BlockCipher* cipher)
37 {
38 return std::max<size_t>(cipher->parallel_bytes(),
39 2 * cipher->block_size());
40 }
41
42 }
43
44 /*
45 * XTS_Encryption constructor
46 */
47 XTS_Encryption::XTS_Encryption(BlockCipher* ciph) :
48 Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
49 cipher(ciph)
50 {
51 if(cipher->block_size() != 8 && cipher->block_size() != 16)
52 throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
53
54 cipher2 = cipher->clone();
55 tweak.resize(buffered_block_size());
56 }
57
58 /*
59 * XTS_Encryption constructor
60 */
61 XTS_Encryption::XTS_Encryption(BlockCipher* ciph,
62 const SymmetricKey& key,
63 const InitializationVector& iv) :
64 Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
65 cipher(ciph)
66 {
67 if(cipher->block_size() != 8 && cipher->block_size() != 16)
68 throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
69
70 cipher2 = cipher->clone();
71 tweak.resize(buffered_block_size());
72
73 set_key(key);
74 set_iv(iv);
75 }
76
77 /*
78 * Return the name
79 */
80 std::string XTS_Encryption::name() const
81 {
82 return (cipher->name() + "/XTS");
83 }
84
85 /*
86 * Set new tweak
87 */
88 void XTS_Encryption::set_iv(const InitializationVector& iv)
89 {
90 if(!valid_iv_length(iv.length()))
91 throw Invalid_IV_Length(name(), iv.length());
92
93 const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
94
95 tweak.copy(iv.begin(), iv.length());
96 cipher2->encrypt(tweak);
97
98 for(size_t i = 1; i < blocks_in_tweak; ++i)
99 {
100 tweak.copy(i*cipher->block_size(),
101 &tweak[(i-1)*cipher->block_size()],
102 cipher->block_size());
103
104 poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
105 }
106 }
107
108 void XTS_Encryption::set_key(const SymmetricKey& key)
109 {
110 size_t key_half = key.length() / 2;
111
112 if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
113 throw Invalid_Key_Length(name(), key.length());
114
115 cipher->set_key(key.begin(), key_half);
116 cipher2->set_key(key.begin() + key_half, key_half);
117 }
118
119 /*
120 * Encrypt in XTS mode
121 */
122 void XTS_Encryption::write(const byte input[], size_t length)
123 {
124 Buffered_Filter::write(input, length);
125 }
126 /*
127 * Finish encrypting in XTS mode
128 */
129 void XTS_Encryption::end_msg()
130 {
131 Buffered_Filter::end_msg();
132 }
133
134 void XTS_Encryption::buffered_block(const byte input[], size_t length)
135 {
136 const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
137 size_t blocks = length / cipher->block_size();
138
139 SecureVector<byte> temp(tweak.size());
140
141 while(blocks)
142 {
143 size_t to_proc = std::min(blocks, blocks_in_tweak);
144 size_t to_proc_bytes = to_proc * cipher->block_size();
145
146 xor_buf(temp, input, tweak, to_proc_bytes);
147
148 cipher->encrypt_n(&temp[0], &temp[0], to_proc);
149
150 xor_buf(temp, tweak, to_proc_bytes);
151
152 send(temp, to_proc_bytes);
153
154 tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
155 cipher->block_size());
156 poly_double(&tweak[0], cipher->block_size());
157
158 for(size_t i = 1; i < blocks_in_tweak; ++i)
159 {
160 tweak.copy(i*cipher->block_size(),
161 &tweak[(i-1)*cipher->block_size()],
162 cipher->block_size());
163
164 poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
165 }
166
167 input += to_proc * cipher->block_size();
168 blocks -= to_proc;
169 }
170 }
171
172 /*
173 * Finish encrypting in XTS mode
174 */
175 void XTS_Encryption::buffered_final(const byte input[], size_t length)
176 {
177 if(length <= cipher->block_size())
178 throw Encoding_Error("XTS_Encryption: insufficient data to encrypt");
179
180 if(length % cipher->block_size() == 0)
181 {
182 buffered_block(input, length);
183 }
184 else
185 { // steal ciphertext
186
187 size_t leftover_blocks =
188 ((length / cipher->block_size()) - 1) * cipher->block_size();
189
190 buffered_block(input, leftover_blocks);
191
192 input += leftover_blocks;
193 length -= leftover_blocks;
194
195 SecureVector<byte> temp(input, length);
196
197 xor_buf(temp, tweak, cipher->block_size());
198 cipher->encrypt(temp);
199 xor_buf(temp, tweak, cipher->block_size());
200
201 poly_double(&tweak[0], cipher->block_size());
202
203 for(size_t i = 0; i != length - cipher->block_size(); ++i)
204 std::swap(temp[i], temp[i + cipher->block_size()]);
205
206 xor_buf(temp, tweak, cipher->block_size());
207 cipher->encrypt(temp);
208 xor_buf(temp, tweak, cipher->block_size());
209
210 send(temp, temp.size());
211 }
212
213 buffer_reset();
214 }
215
216 /*
217 * XTS_Decryption constructor
218 */
219 XTS_Decryption::XTS_Decryption(BlockCipher* ciph) :
220 Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
221 cipher(ciph)
222 {
223 if(cipher->block_size() != 8 && cipher->block_size() != 16)
224 throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
225
226 cipher2 = ciph->clone();
227 tweak.resize(buffered_block_size());
228 }
229
230 /*
231 * XTS_Decryption constructor
232 */
233 XTS_Decryption::XTS_Decryption(BlockCipher* ciph,
234 const SymmetricKey& key,
235 const InitializationVector& iv) :
236 Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
237 cipher(ciph)
238 {
239 if(cipher->block_size() != 8 && cipher->block_size() != 16)
240 throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
241
242 cipher2 = ciph->clone();
243 tweak.resize(buffered_block_size());
244
245 set_key(key);
246 set_iv(iv);
247 }
248
249 /*
250 * Return the name
251 */
252 std::string XTS_Decryption::name() const
253 {
254 return (cipher->name() + "/XTS");
255 }
256
257 /*
258 * Set new tweak
259 */
260 void XTS_Decryption::set_iv(const InitializationVector& iv)
261 {
262 if(!valid_iv_length(iv.length()))
263 throw Invalid_IV_Length(name(), iv.length());
264
265 const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
266
267 tweak.copy(iv.begin(), iv.length());
268 cipher2->encrypt(tweak);
269
270 for(size_t i = 1; i < blocks_in_tweak; ++i)
271 {
272 tweak.copy(i*cipher->block_size(),
273 &tweak[(i-1)*cipher->block_size()],
274 cipher->block_size());
275
276 poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
277 }
278 }
279
280 void XTS_Decryption::set_key(const SymmetricKey& key)
281 {
282 size_t key_half = key.length() / 2;
283
284 if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
285 throw Invalid_Key_Length(name(), key.length());
286
287 cipher->set_key(key.begin(), key_half);
288 cipher2->set_key(key.begin() + key_half, key_half);
289 }
290
291 /*
292 * Decrypt in XTS mode
293 */
294 void XTS_Decryption::write(const byte input[], size_t length)
295 {
296 Buffered_Filter::write(input, length);
297 }
298
299 /*
300 * Finish decrypting in XTS mode
301 */
302 void XTS_Decryption::end_msg()
303 {
304 Buffered_Filter::end_msg();
305 }
306
307 void XTS_Decryption::buffered_block(const byte input[], size_t input_length)
308 {
309 const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
310 size_t blocks = input_length / cipher->block_size();
311
312 SecureVector<byte> temp(tweak.size());
313
314 while(blocks)
315 {
316 size_t to_proc = std::min(blocks, blocks_in_tweak);
317 size_t to_proc_bytes = to_proc * cipher->block_size();
318
319 xor_buf(temp, input, tweak, to_proc_bytes);
320
321 cipher->decrypt_n(&temp[0], &temp[0], to_proc);
322
323 xor_buf(temp, tweak, to_proc_bytes);
324
325 send(temp, to_proc_bytes);
326
327 tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
328 cipher->block_size());
329 poly_double(&tweak[0], cipher->block_size());
330
331 for(size_t i = 1; i < blocks_in_tweak; ++i)
332 {
333 tweak.copy(i*cipher->block_size(),
334 &tweak[(i-1)*cipher->block_size()],
335 cipher->block_size());
336
337 poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
338 }
339
340 input += to_proc * cipher->block_size();
341 blocks -= to_proc;
342 }
343 }
344
345 void XTS_Decryption::buffered_final(const byte input[], size_t length)
346 {
347 if(length <= cipher->block_size())
348 throw Decoding_Error("XTS_Decryption: insufficient data to decrypt");
349
350 if(length % cipher->block_size() == 0)
351 {
352 buffered_block(input, length);
353 }
354 else
355 {
356 size_t leftover_blocks =
357 ((length / cipher->block_size()) - 1) * cipher->block_size();
358
359 buffered_block(input, leftover_blocks);
360
361 input += leftover_blocks;
362 length -= leftover_blocks;
363
364 SecureVector<byte> temp(input, length);
365 SecureVector<byte> tweak_copy(&tweak[0], cipher->block_size());
366
367 poly_double(&tweak_copy[0], cipher->block_size());
368
369 xor_buf(temp, tweak_copy, cipher->block_size());
370 cipher->decrypt(temp);
371 xor_buf(temp, tweak_copy, cipher->block_size());
372
373 for(size_t i = 0; i != length - cipher->block_size(); ++i)
374 std::swap(temp[i], temp[i + cipher->block_size()]);
375
376 xor_buf(temp, tweak, cipher->block_size());
377 cipher->decrypt(temp);
378 xor_buf(temp, tweak, cipher->block_size());
379
380 send(temp, length);
381 }
382
383 buffer_reset();
384 }
385
386 }
Botan::Buffered_Filter
Definition: buf_filt.h:19
Botan::Invalid_Key_Length
Definition: exceptn.h:55
Botan::OctetString
Definition: symkey.h:19
Botan::XTS_Decryption::name
std::string name() const
Definition: xts.cpp:252
Botan::BlockCipher::clone
virtual BlockCipher * clone() const =0
Botan::Buffered_Filter::end_msg
void end_msg()
Definition: buf_filt.cpp:82
Botan::XTS_Encryption::name
std::string name() const
Definition: xts.cpp:80
Botan::Invalid_IV_Length
Definition: exceptn.h:78
Botan::XTS_Encryption::XTS_Encryption
XTS_Encryption(BlockCipher *ciph)
Definition: xts.cpp:47
Botan::Buffered_Filter::write
void write(const byte in[], size_t length)
Definition: buf_filt.cpp:34
Botan::OctetString::begin
const byte * begin() const
Definition: symkey.h:35
Botan::byte
unsigned char byte
Definition: types.h:22
Botan::Filter::send
void send(const byte in[], size_t length)
Definition: filter.cpp:28
Botan::BlockCipher::encrypt
void encrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:47
Botan::SymmetricAlgorithm::set_key
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:60
Botan::XTS_Encryption::set_iv
void set_iv(const InitializationVector &iv)
Definition: xts.cpp:88
Botan
Definition: algo_base.h:14
Botan::OctetString::length
size_t length() const
Definition: symkey.h:25
Botan::XTS_Encryption::valid_iv_length
bool valid_iv_length(size_t iv_len) const
Definition: xts.h:30
Botan::XTS_Decryption::set_iv
void set_iv(const InitializationVector &iv)
Definition: xts.cpp:260
Botan::Buffered_Filter::buffer_reset
void buffer_reset()
Definition: buf_filt.h:77
Botan::XTS_Decryption::XTS_Decryption
XTS_Decryption(BlockCipher *ciph)
Definition: xts.cpp:219
Botan::Buffered_Filter::buffered_block_size
size_t buffered_block_size() const
Definition: buf_filt.h:67
Botan::XTS_Decryption::valid_iv_length
bool valid_iv_length(size_t iv_len) const
Definition: xts.h:67
Botan::CT::min
T min(T a, T b)
Definition: ct_utils.h:127
std::swap
void swap(Botan::MemoryRegion< T > &x, Botan::MemoryRegion< T > &y)
Definition: secmem.h:438
Botan::xor_buf
void xor_buf(byte out[], const byte in[], size_t length)
Definition: xor_buf.h:21
Botan::XTS_Encryption::set_key
void set_key(const SymmetricKey &key)
Definition: xts.cpp:108
Botan::XTS_Decryption::set_key
void set_key(const SymmetricKey &key)
Definition: xts.cpp:280
Botan::BlockCipher
Definition: block_cipher.h:18