Botan  2.12.1
Crypto and TLS for C++11
xts.cpp
Go to the documentation of this file.
1 /*
2 * XTS Mode
3 * (C) 2009,2013 Jack Lloyd
4 * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5 *
6 * Botan is released under the Simplified BSD License (see license.txt)
7 */
8 
9 #include <botan/xts.h>
10 #include <botan/internal/poly_dbl.h>
11 
12 namespace Botan {
13 
15  m_cipher(cipher),
16  m_cipher_block_size(m_cipher->block_size()),
17  m_cipher_parallelism(m_cipher->parallel_bytes())
18  {
19  if(poly_double_supported_size(m_cipher_block_size) == false)
20  {
21  throw Invalid_Argument("Cannot use " + cipher->name() + " with XTS");
22  }
23 
24  m_tweak_cipher.reset(m_cipher->clone());
25  }
26 
28  {
29  m_cipher->clear();
30  m_tweak_cipher->clear();
31  reset();
32  }
33 
35  {
36  m_tweak.clear();
37  }
38 
39 std::string XTS_Mode::name() const
40  {
41  return cipher().name() + "/XTS";
42  }
43 
45  {
46  return cipher_block_size();
47  }
48 
50  {
51  return cipher().key_spec().multiple(2);
52  }
53 
55  {
56  return cipher_block_size();
57  }
58 
59 bool XTS_Mode::valid_nonce_length(size_t n) const
60  {
61  return cipher_block_size() == n;
62  }
63 
64 void XTS_Mode::key_schedule(const uint8_t key[], size_t length)
65  {
66  const size_t key_half = length / 2;
67 
68  if(length % 2 == 1 || !m_cipher->valid_keylength(key_half))
69  throw Invalid_Key_Length(name(), length);
70 
71  m_cipher->set_key(key, key_half);
72  m_tweak_cipher->set_key(&key[key_half], key_half);
73  }
74 
75 void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
76  {
77  if(!valid_nonce_length(nonce_len))
78  throw Invalid_IV_Length(name(), nonce_len);
79 
80  m_tweak.resize(update_granularity());
81  copy_mem(m_tweak.data(), nonce, nonce_len);
82  m_tweak_cipher->encrypt(m_tweak.data());
83 
84  update_tweak(0);
85  }
86 
87 void XTS_Mode::update_tweak(size_t which)
88  {
89  const size_t BS = m_tweak_cipher->block_size();
90 
91  if(which > 0)
92  poly_double_n_le(m_tweak.data(), &m_tweak[(which-1)*BS], BS);
93 
94  const size_t blocks_in_tweak = update_granularity() / BS;
95 
96  for(size_t i = 1; i < blocks_in_tweak; ++i)
97  poly_double_n_le(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS);
98  }
99 
100 size_t XTS_Encryption::output_length(size_t input_length) const
101  {
102  return input_length;
103  }
104 
105 size_t XTS_Encryption::process(uint8_t buf[], size_t sz)
106  {
108  const size_t BS = cipher_block_size();
109 
110  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
111  size_t blocks = sz / BS;
112 
113  const size_t blocks_in_tweak = update_granularity() / BS;
114 
115  while(blocks)
116  {
117  const size_t to_proc = std::min(blocks, blocks_in_tweak);
118 
119  cipher().encrypt_n_xex(buf, tweak(), to_proc);
120 
121  buf += to_proc * BS;
122  blocks -= to_proc;
123 
124  update_tweak(to_proc);
125  }
126 
127  return sz;
128  }
129 
130 void XTS_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
131  {
132  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
133  const size_t sz = buffer.size() - offset;
134  uint8_t* buf = buffer.data() + offset;
135 
136  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS encrypt");
137 
138  const size_t BS = cipher_block_size();
139 
140  if(sz % BS == 0)
141  {
142  update(buffer, offset);
143  }
144  else
145  {
146  // steal ciphertext
147  const size_t full_blocks = ((sz / BS) - 1) * BS;
148  const size_t final_bytes = sz - full_blocks;
149  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
150 
151  secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
152  buffer.resize(full_blocks + offset);
153  update(buffer, offset);
154 
155  xor_buf(last, tweak(), BS);
156  cipher().encrypt(last);
157  xor_buf(last, tweak(), BS);
158 
159  for(size_t i = 0; i != final_bytes - BS; ++i)
160  {
161  last[i] ^= last[i + BS];
162  last[i + BS] ^= last[i];
163  last[i] ^= last[i + BS];
164  }
165 
166  xor_buf(last, tweak() + BS, BS);
167  cipher().encrypt(last);
168  xor_buf(last, tweak() + BS, BS);
169 
170  buffer += last;
171  }
172  }
173 
174 size_t XTS_Decryption::output_length(size_t input_length) const
175  {
176  return input_length;
177  }
178 
179 size_t XTS_Decryption::process(uint8_t buf[], size_t sz)
180  {
182  const size_t BS = cipher_block_size();
183 
184  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
185  size_t blocks = sz / BS;
186 
187  const size_t blocks_in_tweak = update_granularity() / BS;
188 
189  while(blocks)
190  {
191  const size_t to_proc = std::min(blocks, blocks_in_tweak);
192 
193  cipher().decrypt_n_xex(buf, tweak(), to_proc);
194 
195  buf += to_proc * BS;
196  blocks -= to_proc;
197 
198  update_tweak(to_proc);
199  }
200 
201  return sz;
202  }
203 
204 void XTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
205  {
206  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
207  const size_t sz = buffer.size() - offset;
208  uint8_t* buf = buffer.data() + offset;
209 
210  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS decrypt");
211 
212  const size_t BS = cipher_block_size();
213 
214  if(sz % BS == 0)
215  {
216  update(buffer, offset);
217  }
218  else
219  {
220  // steal ciphertext
221  const size_t full_blocks = ((sz / BS) - 1) * BS;
222  const size_t final_bytes = sz - full_blocks;
223  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
224 
225  secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
226  buffer.resize(full_blocks + offset);
227  update(buffer, offset);
228 
229  xor_buf(last, tweak() + BS, BS);
230  cipher().decrypt(last);
231  xor_buf(last, tweak() + BS, BS);
232 
233  for(size_t i = 0; i != final_bytes - BS; ++i)
234  {
235  last[i] ^= last[i + BS];
236  last[i + BS] ^= last[i];
237  last[i] ^= last[i + BS];
238  }
239 
240  xor_buf(last, tweak(), BS);
241  cipher().decrypt(last);
242  xor_buf(last, tweak(), BS);
243 
244  buffer += last;
245  }
246  }
247 
248 }
size_t process(uint8_t buf[], size_t size) override
Definition: xts.cpp:105
size_t cipher_block_size() const
Definition: xts.h:52
void update_tweak(size_t last_used)
Definition: xts.cpp:87
size_t default_nonce_length() const override
Definition: xts.cpp:54
void poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n)
Definition: poly_dbl.cpp:94
void update(secure_vector< uint8_t > &buffer, size_t offset=0)
Definition: cipher_mode.h:112
const BlockCipher & cipher() const
Definition: xts.h:48
#define BOTAN_STATE_CHECK(expr)
Definition: assert.h:49
const uint8_t * tweak() const
Definition: xts.h:44
void decrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:92
size_t output_length(size_t input_length) const override
Definition: xts.cpp:174
std::string name() const override
Definition: xts.cpp:39
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: xts.cpp:130
size_t output_length(size_t input_length) const override
Definition: xts.cpp:100
bool valid_nonce_length(size_t n) const override
Definition: xts.cpp:59
XTS_Mode(BlockCipher *cipher)
Definition: xts.cpp:14
void xor_buf(uint8_t out[], const uint8_t in[], size_t length)
Definition: mem_ops.h:207
virtual std::string name() const =0
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: xts.cpp:204
virtual void encrypt_n_xex(uint8_t data[], const uint8_t mask[], size_t blocks) const
Definition: block_cipher.h:173
void clear() override
Definition: xts.cpp:27
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:122
Definition: alg_id.cpp:13
Key_Length_Specification key_spec() const override
Definition: xts.cpp:49
void encrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:82
virtual Key_Length_Specification key_spec() const =0
bool tweak_set() const
Definition: xts.h:46
size_t minimum_final_size() const override
Definition: xts.cpp:44
Key_Length_Specification multiple(size_t n) const
Definition: key_spec.h:87
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:65
size_t update_granularity() const override
Definition: xts.h:27
size_t process(uint8_t buf[], size_t size) override
Definition: xts.cpp:179
void reset() override
Definition: xts.cpp:34
bool poly_double_supported_size(size_t n)
Definition: poly_dbl.h:22
virtual void decrypt_n_xex(uint8_t data[], const uint8_t mask[], size_t blocks) const
Definition: block_cipher.h:183