Botan  2.7.0
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 
14 XTS_Mode::XTS_Mode(BlockCipher* cipher) : m_cipher(cipher)
15  {
16  if(poly_double_supported_size(m_cipher->block_size()) == false)
17  {
18  throw Invalid_Argument("Cannot use " + cipher->name() + " with XTS");
19  }
20 
21  m_tweak_cipher.reset(m_cipher->clone());
22  m_tweak.resize(update_granularity());
23  }
24 
26  {
27  m_cipher->clear();
28  m_tweak_cipher->clear();
29  reset();
30  }
31 
33  {
34  zeroise(m_tweak);
35  }
36 
37 std::string XTS_Mode::name() const
38  {
39  return cipher().name() + "/XTS";
40  }
41 
43  {
44  return cipher().parallel_bytes();
45  }
46 
48  {
49  return cipher().block_size() + 1;
50  }
51 
53  {
54  return cipher().key_spec().multiple(2);
55  }
56 
58  {
59  return cipher().block_size();
60  }
61 
62 bool XTS_Mode::valid_nonce_length(size_t n) const
63  {
64  return cipher().block_size() == n;
65  }
66 
67 void XTS_Mode::key_schedule(const uint8_t key[], size_t length)
68  {
69  const size_t key_half = length / 2;
70 
71  if(length % 2 == 1 || !m_cipher->valid_keylength(key_half))
72  throw Invalid_Key_Length(name(), length);
73 
74  m_cipher->set_key(key, key_half);
75  m_tweak_cipher->set_key(&key[key_half], key_half);
76  }
77 
78 void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
79  {
80  if(!valid_nonce_length(nonce_len))
81  throw Invalid_IV_Length(name(), nonce_len);
82 
83  copy_mem(m_tweak.data(), nonce, nonce_len);
84  m_tweak_cipher->encrypt(m_tweak.data());
85 
86  update_tweak(0);
87  }
88 
89 void XTS_Mode::update_tweak(size_t which)
90  {
91  const size_t BS = m_tweak_cipher->block_size();
92 
93  if(which > 0)
94  poly_double_n_le(m_tweak.data(), &m_tweak[(which-1)*BS], BS);
95 
96  const size_t blocks_in_tweak = update_granularity() / BS;
97 
98  for(size_t i = 1; i < blocks_in_tweak; ++i)
99  poly_double_n_le(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS);
100  }
101 
102 size_t XTS_Encryption::output_length(size_t input_length) const
103  {
104  return input_length;
105  }
106 
107 size_t XTS_Encryption::process(uint8_t buf[], size_t sz)
108  {
109  const size_t BS = cipher().block_size();
110 
111  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
112  size_t blocks = sz / BS;
113 
114  const size_t blocks_in_tweak = update_granularity() / BS;
115 
116  while(blocks)
117  {
118  const size_t to_proc = std::min(blocks, blocks_in_tweak);
119 
120  cipher().encrypt_n_xex(buf, tweak(), to_proc);
121 
122  buf += to_proc * BS;
123  blocks -= to_proc;
124 
125  update_tweak(to_proc);
126  }
127 
128  return sz;
129  }
130 
131 void XTS_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
132  {
133  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
134  const size_t sz = buffer.size() - offset;
135  uint8_t* buf = buffer.data() + offset;
136 
137  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input in XTS encrypt");
138 
139  const size_t BS = cipher().block_size();
140 
141  if(sz % BS == 0)
142  {
143  update(buffer, offset);
144  }
145  else
146  {
147  // steal ciphertext
148  const size_t full_blocks = ((sz / BS) - 1) * BS;
149  const size_t final_bytes = sz - full_blocks;
150  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
151 
152  secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
153  buffer.resize(full_blocks + offset);
154  update(buffer, offset);
155 
156  xor_buf(last, tweak(), BS);
157  cipher().encrypt(last);
158  xor_buf(last, tweak(), BS);
159 
160  for(size_t i = 0; i != final_bytes - BS; ++i)
161  {
162  last[i] ^= last[i + BS];
163  last[i + BS] ^= last[i];
164  last[i] ^= last[i + BS];
165  }
166 
167  xor_buf(last, tweak() + BS, BS);
168  cipher().encrypt(last);
169  xor_buf(last, tweak() + BS, BS);
170 
171  buffer += last;
172  }
173  }
174 
175 size_t XTS_Decryption::output_length(size_t input_length) const
176  {
177  return input_length;
178  }
179 
180 size_t XTS_Decryption::process(uint8_t buf[], size_t sz)
181  {
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:107
size_t parallel_bytes() const
Definition: block_cipher.h:63
void update_tweak(size_t last_used)
Definition: xts.cpp:89
size_t default_nonce_length() const override
Definition: xts.cpp:57
void update(secure_vector< uint8_t > &buffer, size_t offset=0)
Definition: cipher_mode.h:115
const BlockCipher & cipher() const
Definition: xts.h:44
const uint8_t * tweak() const
Definition: xts.h:42
void decrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:91
size_t output_length(size_t input_length) const override
Definition: xts.cpp:175
std::string name() const override
Definition: xts.cpp:37
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:43
void finish(secure_vector< uint8_t > &final_block, size_t offset=0) override
Definition: xts.cpp:131
size_t output_length(size_t input_length) const override
Definition: xts.cpp:102
bool valid_nonce_length(size_t n) const override
Definition: xts.cpp:62
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:174
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:172
void clear() override
Definition: xts.cpp:25
void poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n)
Definition: poly_dbl.cpp:84
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:108
Definition: alg_id.cpp:13
Key_Length_Specification key_spec() const override
Definition: xts.cpp:52
void encrypt(const uint8_t in[], uint8_t out[]) const
Definition: block_cipher.h:81
virtual Key_Length_Specification key_spec() const =0
size_t minimum_final_size() const override
Definition: xts.cpp:47
Key_Length_Specification multiple(size_t n) const
Definition: key_spec.h:87
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:88
size_t update_granularity() const override
Definition: xts.cpp:42
size_t process(uint8_t buf[], size_t size) override
Definition: xts.cpp:180
void reset() override
Definition: xts.cpp:32
virtual size_t block_size() const =0
bool poly_double_supported_size(size_t n)
Definition: poly_dbl.h:22
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:183
virtual void decrypt_n_xex(uint8_t data[], const uint8_t mask[], size_t blocks) const
Definition: block_cipher.h:182