Botan  1.11.4
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 Key_Length_Specification xts_key_spec(const BlockCipher& cipher)
43  {
44  const Key_Length_Specification& spec = cipher.key_spec();
45 
46  return Key_Length_Specification(2*spec.minimum_keylength(),
47  2*spec.maximum_keylength(),
48  2*spec.keylength_multiple());
49  }
50 
51 }
52 
53 /*
54 * XTS_Encryption constructor
55 */
57  Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
58  cipher(ciph)
59  {
60  if(cipher->block_size() != 8 && cipher->block_size() != 16)
61  throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
62 
63  cipher2 = cipher->clone();
64  tweak.resize(buffered_block_size());
65  }
66 
67 /*
68 * XTS_Encryption constructor
69 */
71  const SymmetricKey& key,
72  const InitializationVector& iv) :
73  Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
74  cipher(ciph)
75  {
76  if(cipher->block_size() != 8 && cipher->block_size() != 16)
77  throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
78 
79  cipher2 = cipher->clone();
80  tweak.resize(buffered_block_size());
81 
82  set_key(key);
83  set_iv(iv);
84  }
85 
86 /*
87 * Return the name
88 */
89 std::string XTS_Encryption::name() const
90  {
91  return (cipher->name() + "/XTS");
92  }
93 
95  {
96  return xts_key_spec(*cipher);
97  }
98 
99 /*
100 * Set new tweak
101 */
103  {
104  if(!valid_iv_length(iv.length()))
105  throw Invalid_IV_Length(name(), iv.length());
106 
107  const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
108 
109  tweak.assign(iv.begin(), iv.end());
110  cipher2->encrypt(tweak);
111 
112  for(size_t i = 1; i < blocks_in_tweak; ++i)
113  {
114  buffer_insert(tweak, i*cipher->block_size(),
115  &tweak[(i-1)*cipher->block_size()],
116  cipher->block_size());
117 
118  poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
119  }
120  }
121 
123  {
124  size_t key_half = key.length() / 2;
125 
126  if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
127  throw Invalid_Key_Length(name(), key.length());
128 
129  cipher->set_key(key.begin(), key_half);
130  cipher2->set_key(key.begin() + key_half, key_half);
131  }
132 
133 /*
134 * Encrypt in XTS mode
135 */
136 void XTS_Encryption::write(const byte input[], size_t length)
137  {
138  Buffered_Filter::write(input, length);
139  }
140 /*
141 * Finish encrypting in XTS mode
142 */
143 void XTS_Encryption::end_msg()
144  {
146  }
147 
148 void XTS_Encryption::buffered_block(const byte input[], size_t length)
149  {
150  const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
151  size_t blocks = length / cipher->block_size();
152 
153  secure_vector<byte> temp(tweak.size());
154 
155  while(blocks)
156  {
157  size_t to_proc = std::min(blocks, blocks_in_tweak);
158  size_t to_proc_bytes = to_proc * cipher->block_size();
159 
160  xor_buf(temp, input, tweak, to_proc_bytes);
161 
162  cipher->encrypt_n(&temp[0], &temp[0], to_proc);
163 
164  xor_buf(temp, tweak, to_proc_bytes);
165 
166  send(temp, to_proc_bytes);
167 
168  copy_mem(&tweak[0],
169  &tweak[(to_proc-1)*cipher->block_size()],
170  cipher->block_size());
171 
172  poly_double(&tweak[0], cipher->block_size());
173 
174  for(size_t i = 1; i < blocks_in_tweak; ++i)
175  {
176  buffer_insert(tweak, i*cipher->block_size(),
177  &tweak[(i-1)*cipher->block_size()],
178  cipher->block_size());
179 
180  poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
181  }
182 
183  input += to_proc * cipher->block_size();
184  blocks -= to_proc;
185  }
186  }
187 
188 /*
189 * Finish encrypting in XTS mode
190 */
191 void XTS_Encryption::buffered_final(const byte input[], size_t length)
192  {
193  if(length <= cipher->block_size())
194  throw Encoding_Error("XTS_Encryption: insufficient data to encrypt");
195 
196  if(length % cipher->block_size() == 0)
197  {
198  buffered_block(input, length);
199  }
200  else
201  { // steal ciphertext
202 
203  size_t leftover_blocks =
204  ((length / cipher->block_size()) - 1) * cipher->block_size();
205 
206  buffered_block(input, leftover_blocks);
207 
208  input += leftover_blocks;
209  length -= leftover_blocks;
210 
211  secure_vector<byte> temp(input, input + length);
212 
213  xor_buf(temp, tweak, cipher->block_size());
214  cipher->encrypt(temp);
215  xor_buf(temp, tweak, cipher->block_size());
216 
217  poly_double(&tweak[0], cipher->block_size());
218 
219  for(size_t i = 0; i != length - cipher->block_size(); ++i)
220  std::swap(temp[i], temp[i + cipher->block_size()]);
221 
222  xor_buf(temp, tweak, cipher->block_size());
223  cipher->encrypt(temp);
224  xor_buf(temp, tweak, cipher->block_size());
225 
226  send(temp, temp.size());
227  }
228 
229  buffer_reset();
230  }
231 
232 /*
233 * XTS_Decryption constructor
234 */
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 
246 /*
247 * XTS_Decryption constructor
248 */
250  const SymmetricKey& key,
251  const InitializationVector& iv) :
252  Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
253  cipher(ciph)
254  {
255  if(cipher->block_size() != 8 && cipher->block_size() != 16)
256  throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
257 
258  cipher2 = ciph->clone();
259  tweak.resize(buffered_block_size());
260 
261  set_key(key);
262  set_iv(iv);
263  }
264 
265 /*
266 * Return the name
267 */
268 std::string XTS_Decryption::name() const
269  {
270  return (cipher->name() + "/XTS");
271  }
272 
274  {
275  return xts_key_spec(*cipher);
276  }
277 
278 /*
279 * Set new tweak
280 */
282  {
283  if(!valid_iv_length(iv.length()))
284  throw Invalid_IV_Length(name(), iv.length());
285 
286  const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
287 
288  tweak.assign(iv.begin(), iv.end());
289  cipher2->encrypt(tweak);
290 
291  for(size_t i = 1; i < blocks_in_tweak; ++i)
292  {
293  buffer_insert(tweak, i*cipher->block_size(),
294  &tweak[(i-1)*cipher->block_size()],
295  cipher->block_size());
296 
297  poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
298  }
299  }
300 
302  {
303  size_t key_half = key.length() / 2;
304 
305  if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
306  throw Invalid_Key_Length(name(), key.length());
307 
308  cipher->set_key(key.begin(), key_half);
309  cipher2->set_key(key.begin() + key_half, key_half);
310  }
311 
312 /*
313 * Decrypt in XTS mode
314 */
315 void XTS_Decryption::write(const byte input[], size_t length)
316  {
317  Buffered_Filter::write(input, length);
318  }
319 
320 /*
321 * Finish decrypting in XTS mode
322 */
323 void XTS_Decryption::end_msg()
324  {
326  }
327 
328 void XTS_Decryption::buffered_block(const byte input[], size_t input_length)
329  {
330  const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
331  size_t blocks = input_length / cipher->block_size();
332 
333  secure_vector<byte> temp(tweak.size());
334 
335  while(blocks)
336  {
337  size_t to_proc = std::min(blocks, blocks_in_tweak);
338  size_t to_proc_bytes = to_proc * cipher->block_size();
339 
340  xor_buf(temp, input, tweak, to_proc_bytes);
341 
342  cipher->decrypt_n(&temp[0], &temp[0], to_proc);
343 
344  xor_buf(temp, tweak, to_proc_bytes);
345 
346  send(temp, to_proc_bytes);
347 
348  copy_mem(&tweak[0],
349  &tweak[(to_proc-1)*cipher->block_size()],
350  cipher->block_size());
351 
352  poly_double(&tweak[0], cipher->block_size());
353 
354  for(size_t i = 1; i < blocks_in_tweak; ++i)
355  {
356  buffer_insert(tweak, i*cipher->block_size(),
357  &tweak[(i-1)*cipher->block_size()],
358  cipher->block_size());
359 
360  poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
361  }
362 
363  input += to_proc * cipher->block_size();
364  blocks -= to_proc;
365  }
366  }
367 
368 void XTS_Decryption::buffered_final(const byte input[], size_t length)
369  {
370  if(length <= cipher->block_size())
371  throw Decoding_Error("XTS_Decryption: insufficient data to decrypt");
372 
373  if(length % cipher->block_size() == 0)
374  {
375  buffered_block(input, length);
376  }
377  else
378  {
379  size_t leftover_blocks =
380  ((length / cipher->block_size()) - 1) * cipher->block_size();
381 
382  buffered_block(input, leftover_blocks);
383 
384  input += leftover_blocks;
385  length -= leftover_blocks;
386 
387  secure_vector<byte> temp(input, input + length);
388  secure_vector<byte> tweak_copy(&tweak[0], &tweak[cipher->block_size()]);
389 
390  poly_double(&tweak_copy[0], cipher->block_size());
391 
392  xor_buf(temp, tweak_copy, cipher->block_size());
393  cipher->decrypt(temp);
394  xor_buf(temp, tweak_copy, cipher->block_size());
395 
396  for(size_t i = 0; i != length - cipher->block_size(); ++i)
397  std::swap(temp[i], temp[i + cipher->block_size()]);
398 
399  xor_buf(temp, tweak, cipher->block_size());
400  cipher->decrypt(temp);
401  xor_buf(temp, tweak, cipher->block_size());
402 
403  send(temp, length);
404  }
405 
406  buffer_reset();
407  }
408 
409 }