Botan  1.10.9
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 */
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 */
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 */
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 
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  {
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 */
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 */
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 */
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 
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  {
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 }
size_t block_size
Definition: ossl_md.cpp:41
virtual BlockCipher * clone() const =0
size_t length() const
Definition: symkey.h:25
XTS_Encryption(BlockCipher *ciph)
Definition: xts.cpp:47
void write(const byte in[], size_t length)
Definition: buf_filt.cpp:34
unsigned char byte
Definition: types.h:22
void send(const byte in[], size_t length)
Definition: filter.cpp:28
void set_key(const SymmetricKey &key)
Definition: sym_algo.h:60
const byte * begin() const
Definition: symkey.h:35
void set_iv(const InitializationVector &iv)
Definition: xts.cpp:88
bool valid_iv_length(size_t iv_len) const
Definition: xts.h:30
bool valid_iv_length(size_t iv_len) const
Definition: xts.h:67
void set_iv(const InitializationVector &iv)
Definition: xts.cpp:260
XTS_Decryption(BlockCipher *ciph)
Definition: xts.cpp:219
void encrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:47
void swap(Botan::MemoryRegion< T > &x, Botan::MemoryRegion< T > &y)
Definition: secmem.h:425
std::string name() const
Definition: xts.cpp:252
void xor_buf(byte out[], const byte in[], size_t length)
Definition: xor_buf.h:21
void set_key(const SymmetricKey &key)
Definition: xts.cpp:108
std::string name() const
Definition: xts.cpp:80
size_t buffered_block_size() const
Definition: buf_filt.h:67
void set_key(const SymmetricKey &key)
Definition: xts.cpp:280