xts.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2018-2020 Mikhail Komarov <nemo@nil.foundation>
3 //
4 // MIT License
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in all
14 // copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 // SOFTWARE.
23 //---------------------------------------------------------------------------//
24 
25 #ifndef CRYPTO3_MODE_XTS_HPP
26 #define CRYPTO3_MODE_XTS_HPP
27 
28 #include <memory>
29 
31 
33 
34 namespace nil {
35  namespace crypto3 {
36  namespace block {
37  namespace modes {
38  namespace detail {
39  template<typename Cipher, typename Padding, template<typename> class Allocator = std::allocator>
40  struct xts_policy {
41  typedef Cipher cipher_type;
42  typedef Padding padding_type;
43 
44  constexpr static const std::size_t block_bits = cipher_type::block_bits;
45  constexpr static const std::size_t block_words = cipher_type::block_words;
46  typedef typename cipher_type::block_type block_type;
47 
48  constexpr static const std::size_t key_bits = cipher_type::key_bits;
49  constexpr static const std::size_t key_words = cipher_type::key_words;
50  typedef typename cipher_type::key_type key_type;
51 
52  static void update_tweak(const cipher_type &tweak_cipher, size_t which) {
53  const size_t BS = tweak_cipher->block_size();
54 
55  if (which > 0) {
56  poly_double_n_le(m_tweak.data(), &m_tweak[(which - 1) * BS], BS);
57  }
58 
59  const size_t blocks_in_tweak = update_granularity() / BS;
60 
61  for (size_t i = 1; i < blocks_in_tweak; ++i) {
62  poly_double_n_le(&m_tweak[i * BS], &m_tweak[(i - 1) * BS], BS);
63  }
64  }
65 
66  static void schedule_key(const key_type &key) {
67  const size_t key_half = length / 2;
68 
69  if (length % 2 == 1 || !m_cipher->valid_keylength(key_half)) {
70  throw invalid_key_length(name(), length);
71  }
72 
73  m_cipher->set_key(key, key_half);
74  m_tweak_cipher->set_key(&key[key_half], key_half);
75  }
76  };
77 
78  template<typename Cipher, typename Padding, typename CiphertextStealingMode>
79  struct xts_encryption_policy : public xts_policy<Cipher, Padding> {};
80 
81  template<typename Cipher, typename Padding>
82  struct xts_encryption_policy<Cipher, Padding, cts<0, Cipher, Padding>>
83  : public xts_policy<Cipher, Padding> {
85 
88 
92 
94  if (!valid_nonce_length(nonce_len)) {
95  throw invalid_iv_length(name(), nonce_len);
96  }
97 
98  copy_mem(m_tweak.data(), nonce, nonce_len);
99  m_tweak_cipher->encrypt(m_tweak.data());
100 
101  update_tweak(0);
102  }
103 
105  const size_t BS = cipher().block_size();
106 
107  BOOST_ASSERT_MSG(sz % BS == 0, "Input is full blocks");
108  size_t blocks = sz / BS;
109 
110  const size_t blocks_in_tweak = update_granularity() / BS;
111 
112  while (blocks) {
113  const size_t to_proc = std::min(blocks, blocks_in_tweak);
114 
115  cipher().encrypt_n_xex(buf, tweak(), to_proc);
116 
117  buf += to_proc * BS;
118  blocks -= to_proc;
119 
120  update_tweak(to_proc);
121  }
122 
123  return sz;
124  }
125 
126  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
127  BOOST_ASSERT_MSG(buffer.size() >= offset, "Offset is sane");
128  const size_t sz = buffer.size() - offset;
129  uint8_t *buf = buffer.data() + offset;
130 
131  BOOST_ASSERT_MSG(sz >= minimum_final_size(), "Have sufficient final input in XTS encipher");
132 
133  const size_t BS = cipher().block_size();
134 
135  if (sz % BS == 0) {
136  update(buffer, offset);
137  } else {
138  // steal ciphertext
139  const size_t full_blocks = ((sz / BS) - 1) * BS;
140  const size_t final_bytes = sz - full_blocks;
141  BOOST_ASSERT_MSG(final_bytes > BS && final_bytes < 2 * BS,
142  "Left over size in expected range");
143 
144  secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
145  buffer.resize(full_blocks + offset);
146  update(buffer, offset);
147 
148  xor_buf(last, tweak(), BS);
149  cipher().encrypt(last);
150  xor_buf(last, tweak(), BS);
151 
152  for (size_t i = 0; i != final_bytes - BS; ++i) {
153  last[i] ^= last[i + BS];
154  last[i + BS] ^= last[i];
155  last[i] ^= last[i + BS];
156  }
157 
158  xor_buf(last, tweak() + BS, BS);
159  cipher().encrypt(last);
160  xor_buf(last, tweak() + BS, BS);
161 
162  buffer += last;
163  }
164  }
165  };
166 
167  template<typename Cipher, typename Padding>
168  struct xts_encryption_policy<Cipher, Padding, cts<1, Cipher, Padding>>
169  : public xts_policy<Cipher, Padding> {
171 
174 
178 
180  return cipher.encrypt(plaintext);
181  }
182 
184  return cipher.encrypt(plaintext);
185  }
186 
187  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
188  return {};
189  }
190  };
191 
192  template<typename Cipher, typename Padding>
193  struct xts_encryption_policy<Cipher, Padding, cts<2, Cipher, Padding>>
194  : public xts_policy<Cipher, Padding> {
196 
199 
203 
205  return cipher.encrypt(plaintext);
206  }
207 
209  return cipher.encrypt(plaintext);
210  }
211 
212  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
213  return {};
214  }
215  };
216 
217  template<typename Cipher, typename Padding>
218  struct xts_encryption_policy<Cipher, Padding, cts<3, Cipher, Padding>>
219  : public xts_policy<Cipher, Padding> {
221 
224 
228 
230  return cipher.encrypt(plaintext);
231  }
232 
234  return cipher.encrypt(plaintext);
235  }
236 
237  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
238  return {};
239  }
240  };
241 
242  template<typename Cipher, typename Padding, typename CiphertextStealingMode>
243  struct xts_decryption_policy : public xts_policy<Cipher, Padding> {};
244 
245  template<typename Cipher, typename Padding>
246  struct xts_decryption_policy<Cipher, Padding, cts<0, Cipher, Padding>>
247  : public xts_policy<Cipher, Padding> {
249 
252 
256 
258  if (!valid_nonce_length(nonce_len)) {
259  throw invalid_iv_length(name(), nonce_len);
260  }
261 
262  copy_mem(m_tweak.data(), nonce, nonce_len);
263  m_tweak_cipher->encrypt(m_tweak.data());
264 
265  update_tweak(0);
266  }
267 
269  BOOST_ASSERT_MSG(buffer.size() >= offset, "Offset is sane");
270  const size_t sz = buffer.size() - offset;
271  uint8_t *buf = buffer.data() + offset;
272 
273  BOOST_ASSERT_MSG(sz >= minimum_final_size(), "Have sufficient final input in XTS isomorphic_decryption_mode");
274 
275  const size_t BS = cipher.block_size();
276 
277  if (sz % BS == 0) {
278  update(buffer, offset);
279  } else {
280  // steal ciphertext
281  const size_t full_blocks = ((sz / BS) - 1) * BS;
282  const size_t final_bytes = sz - full_blocks;
283  BOOST_ASSERT_MSG(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
284 
285  secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
286  buffer.resize(full_blocks + offset);
287  update(buffer, offset);
288 
289  xor_buf(last, tweak() + BS, BS);
290  cipher.decrypt(last);
291  xor_buf(last, tweak() + BS, BS);
292 
293  for (size_t i = 0; i != final_bytes - BS; ++i) {
294  last[i] ^= last[i + BS];
295  last[i + BS] ^= last[i];
296  last[i] ^= last[i + BS];
297  }
298 
299  xor_buf(last, tweak(), BS);
300  cipher.decrypt(last);
301  xor_buf(last, tweak(), BS);
302 
303  buffer += last;
304  }
305  }
306 
307  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
308  const size_t BS = cipher().block_size();
309 
310  BOOST_ASSERT_MSG(sz % BS == 0, "Input is full blocks");
311  size_t blocks = sz / BS;
312 
313  const size_t blocks_in_tweak = update_granularity() / BS;
314 
315  while (blocks) {
316  const size_t to_proc = std::min(blocks, blocks_in_tweak);
317 
318  cipher().encrypt_n_xex(buf, tweak(), to_proc);
319 
320  buf += to_proc * BS;
321  blocks -= to_proc;
322 
323  update_tweak(to_proc);
324  }
325 
326  return sz;
327  }
328  };
329 
330  template<typename Cipher, typename Padding>
331  struct xts_decryption_policy<Cipher, Padding, cts<1, Cipher, Padding>>
332  : public xts_policy<Cipher, Padding> {
334 
337 
341 
343  return cipher.decrypt(plaintext);
344  }
345 
347  return cipher.decrypt(plaintext);
348  }
349 
350  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
351  return {};
352  }
353  };
354 
355  template<typename Cipher, typename Padding>
356  struct xts_decryption_policy<Cipher, Padding, cts<2, Cipher, Padding>>
357  : public xts_policy<Cipher, Padding> {
359 
362 
366 
368  return cipher.decrypt(plaintext);
369  }
370 
372  return cipher.decrypt(plaintext);
373  }
374 
375  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
376  return {};
377  }
378  };
379 
380  template<typename Cipher, typename Padding>
381  struct xts_decryption_policy<Cipher, Padding, cts<3, Cipher, Padding>>
382  : public xts_policy<Cipher, Padding> {
384 
387 
391 
393  return cipher.decrypt(plaintext);
394  }
395 
397  return cipher.decrypt(plaintext);
398  }
399 
400  block_type end_message(const cipher_type &cipher, const block_type &plaintext) {
401  return {};
402  }
403  };
404 
405  // Electronic Code Book CodecMode (ECB)
406  template<typename Policy>
407  class xts {
408  typedef Policy policy_type;
409 
410  public:
411  typedef typename policy_type::cipher_type cipher_type;
412  typedef typename policy_type::padding_type padding_type;
413 
414  typedef typename policy_type::size_type size_type;
415 
416  constexpr static const std::size_t block_bits = policy_type::block_bits;
417  constexpr static const std::size_t block_words = policy_type::block_words;
418  typedef typename cipher_type::block_type block_type;
419 
420  xts(const cipher_type &c) : cipher(c) {
421  }
422 
423  block_type begin_message(const block_type &plaintext) {
424  return policy_type::begin_message(cipher, plaintext);
425  }
426 
427  block_type process_block(const block_type &plaintext) {
428  return policy_type::process_block(cipher, plaintext);
429  }
430 
431  block_type end_message(const block_type &plaintext) {
432  return policy_type::end_message(cipher, plaintext);
433  }
434 
436  return padding_type::required_output_size(inputlen, block_size);
437  }
438 
439  constexpr static const std::size_t key_length = cipher_type::key_length / 8;
440  constexpr static const std::size_t block_size = cipher_type::block_size / 8;
441 
442  private:
443  cipher_type cipher, tweak_cipher;
444  };
445  } // namespace detail
446 
455  template<typename Cipher, template<typename> class Padding,
456  template<typename, typename> class CiphertextStealingMode = cts0>
457  struct xts {
458  typedef Cipher cipher_type;
459  typedef Padding<Cipher> padding_type;
460  typedef CiphertextStealingMode<Cipher, Padding<Cipher>> ciphertext_stealing_type;
461 
466 
467  template<template<typename, typename> class Policy>
468  struct bind {
470  };
471  };
472  } // namespace modes
473  } // namespace block
474  } // namespace crypto3
475 } // namespace nil
476 
477 #endif
block_type begin_message(const block_type &plaintext)
Definition: xts.hpp:423
policy_type::padding_type padding_type
Definition: xts.hpp:412
cipher_type::block_type block_type
Definition: xts.hpp:418
constexpr static const std::size_t block_size
Definition: xts.hpp:440
policy_type::cipher_type cipher_type
Definition: xts.hpp:411
block_type process_block(const block_type &plaintext)
Definition: xts.hpp:427
block_type end_message(const block_type &plaintext)
Definition: xts.hpp:431
policy_type::size_type size_type
Definition: xts.hpp:414
size_type required_output_size(size_type inputlen) const
Definition: xts.hpp:435
constexpr static const std::size_t block_words
Definition: xts.hpp:417
constexpr static const std::size_t block_bits
Definition: xts.hpp:416
xts(const cipher_type &c)
Definition: xts.hpp:420
constexpr static const std::size_t key_length
Definition: xts.hpp:439
constexpr T min(const vector< T, N > &v)
computes the minimum valued element
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:135
boost::mpl::apply< AccumulatorSet, tag::block< Mode > >::type::result_type block(const AccumulatorSet &acc)
Definition: accumulators/block.hpp:259
void poly_double_n_le(uint8_t out[], InputIterator first, InputIterator last)
Definition: mac/include/nil/crypto3/detail/poly_dbl.hpp:118
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: memory_operations.hpp:245
void copy_mem(T *out, const T *in, size_t n)
Definition: memory_operations.hpp:186
Definition: pair.hpp:31
Definition: cipher.hpp:38
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:400
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:392
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:386
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:396
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:257
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:268
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:251
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:307
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:342
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:346
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:350
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:336
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:375
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:371
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:367
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:361
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:198
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:204
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:212
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:208
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:223
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:233
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:237
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:229
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:104
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:87
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:126
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:93
block_type end_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:187
block_type process_block(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:183
block_type begin_message(const cipher_type &cipher, const block_type &plaintext)
Definition: xts.hpp:179
xts_policy< Cipher, Padding >::padding_type padding_type
Definition: xts.hpp:173
constexpr static const std::size_t key_bits
Definition: xts.hpp:48
static void schedule_key(const key_type &key)
Definition: xts.hpp:66
constexpr static const std::size_t block_bits
Definition: xts.hpp:44
cipher_type::key_type key_type
Definition: xts.hpp:50
constexpr static const std::size_t block_words
Definition: xts.hpp:45
Padding padding_type
Definition: xts.hpp:42
constexpr static const std::size_t key_words
Definition: xts.hpp:49
cipher_type::block_type block_type
Definition: xts.hpp:46
Cipher cipher_type
Definition: xts.hpp:41
static void update_tweak(const cipher_type &tweak_cipher, size_t which)
Definition: xts.hpp:52
detail::xts< Policy< cipher_type, padding_type > > type
Definition: xts.hpp:469
IEEE P1619 XTS Mode.
Definition: xts.hpp:457
CiphertextStealingMode< Cipher, Padding< Cipher > > ciphertext_stealing_type
Definition: xts.hpp:460
detail::xts_decryption_policy< cipher_type, padding_type, ciphertext_stealing_type > decryption_policy
Definition: xts.hpp:465
Padding< Cipher > padding_type
Definition: xts.hpp:459
Cipher cipher_type
Definition: xts.hpp:458
detail::xts_encryption_policy< cipher_type, padding_type, ciphertext_stealing_type > encryption_policy
Definition: xts.hpp:463