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