Botan  1.11.10
xts.cpp
Go to the documentation of this file.
1 /*
2 * XTS Mode
3 * (C) 2009,2013 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/xts.h>
9 #include <botan/loadstor.h>
10 #include <botan/internal/xor_buf.h>
11 #include <botan/internal/rounding.h>
12 
13 namespace Botan {
14 
15 namespace {
16 
17 void poly_double_128(byte out[], const byte in[])
18  {
19  u64bit X0 = load_le<u64bit>(in, 0);
20  u64bit X1 = load_le<u64bit>(in, 1);
21 
22  const bool carry = (X1 >> 63);
23 
24  X1 = (X1 << 1) | (X0 >> 63);
25  X0 = (X0 << 1);
26 
27  if(carry)
28  X0 ^= 0x87;
29 
30  store_le(out, X0, X1);
31  }
32 
33 void poly_double_64(byte out[], const byte in[])
34  {
35  u64bit X = load_le<u64bit>(in, 0);
36  const bool carry = (X >> 63);
37  X <<= 1;
38  if(carry)
39  X ^= 0x1B;
40  store_le(X, out);
41  }
42 
43 inline void poly_double(byte out[], const byte in[], size_t size)
44  {
45  if(size == 8)
46  poly_double_64(out, in);
47  else
48  poly_double_128(out, in);
49  }
50 
51 }
52 
53 XTS_Mode::XTS_Mode(BlockCipher* cipher) : m_cipher(cipher)
54  {
55  if(m_cipher->block_size() != 8 && m_cipher->block_size() != 16)
56  throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
57 
58  m_tweak_cipher.reset(m_cipher->clone());
59  m_tweak.resize(update_granularity());
60  }
61 
63  {
64  m_cipher->clear();
65  m_tweak_cipher->clear();
66  zeroise(m_tweak);
67  }
68 
69 std::string XTS_Mode::name() const
70  {
71  return cipher().name() + "/XTS";
72  }
73 
75  {
76  return cipher().parallel_bytes();
77  }
78 
80  {
81  return cipher().block_size() + 1;
82  }
83 
85  {
86  return cipher().key_spec().multiple(2);
87  }
88 
90  {
91  return cipher().block_size();
92  }
93 
94 bool XTS_Mode::valid_nonce_length(size_t n) const
95  {
96  return cipher().block_size() == n;
97  }
98 
99 void XTS_Mode::key_schedule(const byte key[], size_t length)
100  {
101  const size_t key_half = length / 2;
102 
103  if(length % 2 == 1 || !m_cipher->valid_keylength(key_half))
104  throw Invalid_Key_Length(name(), length);
105 
106  m_cipher->set_key(&key[0], key_half);
107  m_tweak_cipher->set_key(&key[key_half], key_half);
108  }
109 
110 secure_vector<byte> XTS_Mode::start(const byte nonce[], size_t nonce_len)
111  {
112  if(!valid_nonce_length(nonce_len))
113  throw Invalid_IV_Length(name(), nonce_len);
114 
115  copy_mem(&m_tweak[0], nonce, nonce_len);
116  m_tweak_cipher->encrypt(&m_tweak[0]);
117 
118  update_tweak(0);
119 
120  return secure_vector<byte>();
121  }
122 
123 void XTS_Mode::update_tweak(size_t which)
124  {
125  const size_t BS = m_tweak_cipher->block_size();
126 
127  if(which > 0)
128  poly_double(&m_tweak[0], &m_tweak[(which-1)*BS], BS);
129 
130  const size_t blocks_in_tweak = update_granularity() / BS;
131 
132  for(size_t i = 1; i < blocks_in_tweak; ++i)
133  poly_double(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS);
134  }
135 
136 size_t XTS_Encryption::output_length(size_t input_length) const
137  {
138  return round_up(input_length, cipher().block_size());
139  }
140 
141 void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset)
142  {
143  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
144  const size_t sz = buffer.size() - offset;
145  byte* buf = &buffer[offset];
146 
147  const size_t BS = cipher().block_size();
148 
149  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
150  size_t blocks = sz / BS;
151 
152  const size_t blocks_in_tweak = update_granularity() / BS;
153 
154  while(blocks)
155  {
156  const size_t to_proc = std::min(blocks, blocks_in_tweak);
157  const size_t to_proc_bytes = to_proc * BS;
158 
159  xor_buf(buf, tweak(), to_proc_bytes);
160  cipher().encrypt_n(buf, buf, to_proc);
161  xor_buf(buf, tweak(), to_proc_bytes);
162 
163  buf += to_proc * BS;
164  blocks -= to_proc;
165 
166  update_tweak(to_proc);
167  }
168  }
169 
170 void XTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
171  {
172  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
173  const size_t sz = buffer.size() - offset;
174  byte* buf = &buffer[offset];
175 
176  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input");
177 
178  const size_t BS = cipher().block_size();
179 
180  if(sz % BS == 0)
181  {
182  update(buffer, offset);
183  }
184  else
185  {
186  // steal ciphertext
187  const size_t full_blocks = ((sz / BS) - 1) * BS;
188  const size_t final_bytes = sz - full_blocks;
189  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
190 
191  secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes);
192  buffer.resize(full_blocks + offset);
193  update(buffer, offset);
194 
195  xor_buf(last, tweak(), BS);
196  cipher().encrypt(last);
197  xor_buf(last, tweak(), BS);
198 
199  for(size_t i = 0; i != final_bytes - BS; ++i)
200  {
201  last[i] ^= last[i + BS];
202  last[i + BS] ^= last[i];
203  last[i] ^= last[i + BS];
204  }
205 
206  xor_buf(last, tweak() + BS, BS);
207  cipher().encrypt(last);
208  xor_buf(last, tweak() + BS, BS);
209 
210  buffer += last;
211  }
212  }
213 
214 size_t XTS_Decryption::output_length(size_t input_length) const
215  {
216  // might be less
217  return input_length;
218  }
219 
220 void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset)
221  {
222  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
223  const size_t sz = buffer.size() - offset;
224  byte* buf = &buffer[offset];
225 
226  const size_t BS = cipher().block_size();
227 
228  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
229  size_t blocks = sz / BS;
230 
231  const size_t blocks_in_tweak = update_granularity() / BS;
232 
233  while(blocks)
234  {
235  const size_t to_proc = std::min(blocks, blocks_in_tweak);
236  const size_t to_proc_bytes = to_proc * BS;
237 
238  xor_buf(buf, tweak(), to_proc_bytes);
239  cipher().decrypt_n(buf, buf, to_proc);
240  xor_buf(buf, tweak(), to_proc_bytes);
241 
242  buf += to_proc * BS;
243  blocks -= to_proc;
244 
245  update_tweak(to_proc);
246  }
247  }
248 
249 void XTS_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
250  {
251  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
252  const size_t sz = buffer.size() - offset;
253  byte* buf = &buffer[offset];
254 
255  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input");
256 
257  const size_t BS = cipher().block_size();
258 
259  if(sz % BS == 0)
260  {
261  update(buffer, offset);
262  }
263  else
264  {
265  // steal ciphertext
266  const size_t full_blocks = ((sz / BS) - 1) * BS;
267  const size_t final_bytes = sz - full_blocks;
268  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
269 
270  secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes);
271  buffer.resize(full_blocks + offset);
272  update(buffer, offset);
273 
274  xor_buf(last, tweak() + BS, BS);
275  cipher().decrypt(last);
276  xor_buf(last, tweak() + BS, BS);
277 
278  for(size_t i = 0; i != final_bytes - BS; ++i)
279  {
280  last[i] ^= last[i + BS];
281  last[i + BS] ^= last[i];
282  last[i] ^= last[i + BS];
283  }
284 
285  xor_buf(last, tweak(), BS);
286  cipher().decrypt(last);
287  xor_buf(last, tweak(), BS);
288 
289  buffer += last;
290  }
291  }
292 
293 }
void xor_buf(T out[], const T in[], size_t length)
Definition: xor_buf.h:23
void decrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:57
secure_vector< byte > start(const byte nonce[], size_t nonce_len) override
Definition: xts.cpp:110
void update_tweak(size_t last_used)
Definition: xts.cpp:123
size_t default_nonce_length() const override
Definition: xts.cpp:89
void store_le(u16bit in, byte out[2])
Definition: loadstor.h:427
size_t output_length(size_t input_length) const override
Definition: xts.cpp:214
std::string name() const override
Definition: xts.cpp:69
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
void update(secure_vector< byte > &blocks, size_t offset=0) override
Definition: xts.cpp:220
size_t output_length(size_t input_length) const override
Definition: xts.cpp:136
bool valid_nonce_length(size_t n) const override
Definition: xts.cpp:94
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:92
void finish(secure_vector< byte > &final_block, size_t offset=0) override
Definition: xts.cpp:249
void finish(secure_vector< byte > &final_block, size_t offset=0) override
Definition: xts.cpp:170
XTS_Mode(BlockCipher *cipher)
Definition: xts.cpp:53
virtual std::string name() const =0
Key_Length_Specification multiple(size_t n) const
Definition: key_spec.h:82
void clear() override
Definition: xts.cpp:62
uint8_t byte
Definition: types.h:30
size_t parallel_bytes() const
Definition: block_cipher.h:35
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:39
Definition: buf_comp.h:15
Key_Length_Specification key_spec() const override
Definition: xts.cpp:84
const BlockCipher & cipher() const
Definition: xts.h:42
virtual Key_Length_Specification key_spec() const =0
T round_up(T n, T align_to)
Definition: rounding.h:22
size_t minimum_final_size() const override
Definition: xts.cpp:79
void update(secure_vector< byte > &blocks, size_t offset=0) override
Definition: xts.cpp:141
void encrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:47
virtual void encrypt_n(const byte in[], byte out[], size_t blocks) const =0
uint64_t u64bit
Definition: types.h:33
size_t update_granularity() const override
Definition: xts.cpp:74
virtual void decrypt_n(const byte in[], byte out[], size_t blocks) const =0
const byte * tweak() const
Definition: xts.h:40
virtual size_t block_size() const =0
u64bit load_le< u64bit >(const byte in[], size_t off)
Definition: loadstor.h:218
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:166