Botan  1.11.30
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 secure_vector<byte> XTS_Mode::start_raw(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  return secure_vector<byte>();
119  }
120 
121 void XTS_Mode::update_tweak(size_t which)
122  {
123  const size_t BS = m_tweak_cipher->block_size();
124 
125  if(which > 0)
126  poly_double(m_tweak.data(), &m_tweak[(which-1)*BS], BS);
127 
128  const size_t blocks_in_tweak = update_granularity() / BS;
129 
130  for(size_t i = 1; i < blocks_in_tweak; ++i)
131  poly_double(&m_tweak[i*BS], &m_tweak[(i-1)*BS], BS);
132  }
133 
134 size_t XTS_Encryption::output_length(size_t input_length) const
135  {
136  return input_length;
137  }
138 
139 void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset)
140  {
141  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
142  const size_t sz = buffer.size() - offset;
143  byte* buf = buffer.data() + offset;
144 
145  const size_t BS = cipher().block_size();
146 
147  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
148  size_t blocks = sz / BS;
149 
150  const size_t blocks_in_tweak = update_granularity() / BS;
151 
152  while(blocks)
153  {
154  const size_t to_proc = std::min(blocks, blocks_in_tweak);
155  const size_t to_proc_bytes = to_proc * BS;
156 
157  xor_buf(buf, tweak(), to_proc_bytes);
158  cipher().encrypt_n(buf, buf, to_proc);
159  xor_buf(buf, tweak(), to_proc_bytes);
160 
161  buf += to_proc * BS;
162  blocks -= to_proc;
163 
164  update_tweak(to_proc);
165  }
166  }
167 
168 void XTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
169  {
170  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
171  const size_t sz = buffer.size() - offset;
172  byte* buf = buffer.data() + offset;
173 
174  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input");
175 
176  const size_t BS = cipher().block_size();
177 
178  if(sz % BS == 0)
179  {
180  update(buffer, offset);
181  }
182  else
183  {
184  // steal ciphertext
185  const size_t full_blocks = ((sz / BS) - 1) * BS;
186  const size_t final_bytes = sz - full_blocks;
187  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
188 
189  secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes);
190  buffer.resize(full_blocks + offset);
191  update(buffer, offset);
192 
193  xor_buf(last, tweak(), BS);
194  cipher().encrypt(last);
195  xor_buf(last, tweak(), BS);
196 
197  for(size_t i = 0; i != final_bytes - BS; ++i)
198  {
199  last[i] ^= last[i + BS];
200  last[i + BS] ^= last[i];
201  last[i] ^= last[i + BS];
202  }
203 
204  xor_buf(last, tweak() + BS, BS);
205  cipher().encrypt(last);
206  xor_buf(last, tweak() + BS, BS);
207 
208  buffer += last;
209  }
210  }
211 
212 size_t XTS_Decryption::output_length(size_t input_length) const
213  {
214  return input_length;
215  }
216 
217 void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset)
218  {
219  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
220  const size_t sz = buffer.size() - offset;
221  byte* buf = buffer.data() + offset;
222 
223  const size_t BS = cipher().block_size();
224 
225  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
226  size_t blocks = sz / BS;
227 
228  const size_t blocks_in_tweak = update_granularity() / BS;
229 
230  while(blocks)
231  {
232  const size_t to_proc = std::min(blocks, blocks_in_tweak);
233  const size_t to_proc_bytes = to_proc * BS;
234 
235  xor_buf(buf, tweak(), to_proc_bytes);
236  cipher().decrypt_n(buf, buf, to_proc);
237  xor_buf(buf, tweak(), to_proc_bytes);
238 
239  buf += to_proc * BS;
240  blocks -= to_proc;
241 
242  update_tweak(to_proc);
243  }
244  }
245 
246 void XTS_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
247  {
248  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
249  const size_t sz = buffer.size() - offset;
250  byte* buf = buffer.data() + offset;
251 
252  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input");
253 
254  const size_t BS = cipher().block_size();
255 
256  if(sz % BS == 0)
257  {
258  update(buffer, offset);
259  }
260  else
261  {
262  // steal ciphertext
263  const size_t full_blocks = ((sz / BS) - 1) * BS;
264  const size_t final_bytes = sz - full_blocks;
265  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
266 
267  secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes);
268  buffer.resize(full_blocks + offset);
269  update(buffer, offset);
270 
271  xor_buf(last, tweak() + BS, BS);
272  cipher().decrypt(last);
273  xor_buf(last, tweak() + BS, BS);
274 
275  for(size_t i = 0; i != final_bytes - BS; ++i)
276  {
277  last[i] ^= last[i + BS];
278  last[i + BS] ^= last[i];
279  last[i] ^= last[i + BS];
280  }
281 
282  xor_buf(last, tweak(), BS);
283  cipher().decrypt(last);
284  xor_buf(last, tweak(), BS);
285 
286  buffer += last;
287  }
288  }
289 
290 }
void xor_buf(T out[], const T in[], size_t length)
Definition: mem_ops.h:90
virtual void update(secure_vector< byte > &blocks, size_t offset=0)=0
void decrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:72
void update_tweak(size_t last_used)
Definition: xts.cpp:121
size_t default_nonce_length() const override
Definition: xts.cpp:87
void store_le(u16bit in, byte out[2])
Definition: loadstor.h:461
size_t output_length(size_t input_length) const override
Definition: xts.cpp:212
std::string name() const override
Definition: xts.cpp:67
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
void update(secure_vector< byte > &blocks, size_t offset=0) override
Definition: xts.cpp:217
std::uint64_t u64bit
Definition: types.h:34
size_t output_length(size_t input_length) const override
Definition: xts.cpp:134
bool valid_nonce_length(size_t n) const override
Definition: xts.cpp:92
std::vector< T, secure_allocator< T >> secure_vector
Definition: secmem.h:96
void finish(secure_vector< byte > &final_block, size_t offset=0) override
Definition: xts.cpp:246
void finish(secure_vector< byte > &final_block, size_t offset=0) override
Definition: xts.cpp:168
XTS_Mode(BlockCipher *cipher)
Definition: xts.cpp:51
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:60
size_t parallel_bytes() const
Definition: block_cipher.h:50
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
const BlockCipher & cipher() const
Definition: xts.h:40
virtual Key_Length_Specification key_spec() const =0
size_t minimum_final_size() const override
Definition: xts.cpp:77
void update(secure_vector< byte > &blocks, size_t offset=0) override
Definition: xts.cpp:139
void encrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:62
T min(T a, T b)
Definition: ct_utils.h:180
virtual void encrypt_n(const byte in[], byte out[], size_t blocks) const =0
size_t update_granularity() const override
Definition: xts.cpp:72
virtual void decrypt_n(const byte in[], byte out[], size_t blocks) const =0
const byte * tweak() const
Definition: xts.h:38
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:186
std::uint8_t byte
Definition: types.h:31