Botan  1.10.10
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 BOTAN_REGISTER_BLOCK_CIPHER_MODE(XTS_Encryption, XTS_Decryption);
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 = static_cast<bool>((X1 >> 63) != 0);
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 = static_cast<bool>((X >> 63) != 0);
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, key_half);
107  m_tweak_cipher->set_key(&key[key_half], key_half);
108  }
109 
110 secure_vector<byte> XTS_Mode::start_raw(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.data(), nonce, nonce_len);
116  m_tweak_cipher->encrypt(m_tweak.data());
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.data(), &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  BOTAN_ASSERT(input_length != 0, "XTS_Encryption::output_length() call");
139  return round_up(input_length, cipher().block_size());
140  }
141 
142 void XTS_Encryption::update(secure_vector<byte>& buffer, size_t offset)
143  {
144  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
145  const size_t sz = buffer.size() - offset;
146  byte* buf = buffer.data() + offset;
147 
148  const size_t BS = cipher().block_size();
149 
150  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
151  size_t blocks = sz / BS;
152 
153  const size_t blocks_in_tweak = update_granularity() / BS;
154 
155  while(blocks)
156  {
157  const size_t to_proc = std::min(blocks, blocks_in_tweak);
158  const size_t to_proc_bytes = to_proc * BS;
159 
160  xor_buf(buf, tweak(), to_proc_bytes);
161  cipher().encrypt_n(buf, buf, to_proc);
162  xor_buf(buf, tweak(), to_proc_bytes);
163 
164  buf += to_proc * BS;
165  blocks -= to_proc;
166 
167  update_tweak(to_proc);
168  }
169  }
170 
171 void XTS_Encryption::finish(secure_vector<byte>& buffer, size_t offset)
172  {
173  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
174  const size_t sz = buffer.size() - offset;
175  byte* buf = buffer.data() + offset;
176 
177  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input");
178 
179  const size_t BS = cipher().block_size();
180 
181  if(sz % BS == 0)
182  {
183  update(buffer, offset);
184  }
185  else
186  {
187  // steal ciphertext
188  const size_t full_blocks = ((sz / BS) - 1) * BS;
189  const size_t final_bytes = sz - full_blocks;
190  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
191 
192  secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes);
193  buffer.resize(full_blocks + offset);
194  update(buffer, offset);
195 
196  xor_buf(last, tweak(), BS);
197  cipher().encrypt(last);
198  xor_buf(last, tweak(), BS);
199 
200  for(size_t i = 0; i != final_bytes - BS; ++i)
201  {
202  last[i] ^= last[i + BS];
203  last[i + BS] ^= last[i];
204  last[i] ^= last[i + BS];
205  }
206 
207  xor_buf(last, tweak() + BS, BS);
208  cipher().encrypt(last);
209  xor_buf(last, tweak() + BS, BS);
210 
211  buffer += last;
212  }
213  }
214 
215 size_t XTS_Decryption::output_length(size_t input_length) const
216  {
217  // might be less
218  return input_length;
219  }
220 
221 void XTS_Decryption::update(secure_vector<byte>& buffer, size_t offset)
222  {
223  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
224  const size_t sz = buffer.size() - offset;
225  byte* buf = buffer.data() + offset;
226 
227  const size_t BS = cipher().block_size();
228 
229  BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
230  size_t blocks = sz / BS;
231 
232  const size_t blocks_in_tweak = update_granularity() / BS;
233 
234  while(blocks)
235  {
236  const size_t to_proc = std::min(blocks, blocks_in_tweak);
237  const size_t to_proc_bytes = to_proc * BS;
238 
239  xor_buf(buf, tweak(), to_proc_bytes);
240  cipher().decrypt_n(buf, buf, to_proc);
241  xor_buf(buf, tweak(), to_proc_bytes);
242 
243  buf += to_proc * BS;
244  blocks -= to_proc;
245 
246  update_tweak(to_proc);
247  }
248  }
249 
250 void XTS_Decryption::finish(secure_vector<byte>& buffer, size_t offset)
251  {
252  BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
253  const size_t sz = buffer.size() - offset;
254  byte* buf = buffer.data() + offset;
255 
256  BOTAN_ASSERT(sz >= minimum_final_size(), "Have sufficient final input");
257 
258  const size_t BS = cipher().block_size();
259 
260  if(sz % BS == 0)
261  {
262  update(buffer, offset);
263  }
264  else
265  {
266  // steal ciphertext
267  const size_t full_blocks = ((sz / BS) - 1) * BS;
268  const size_t final_bytes = sz - full_blocks;
269  BOTAN_ASSERT(final_bytes > BS && final_bytes < 2*BS, "Left over size in expected range");
270 
271  secure_vector<byte> last(buf + full_blocks, buf + full_blocks + final_bytes);
272  buffer.resize(full_blocks + offset);
273  update(buffer, offset);
274 
275  xor_buf(last, tweak() + BS, BS);
276  cipher().decrypt(last);
277  xor_buf(last, tweak() + BS, BS);
278 
279  for(size_t i = 0; i != final_bytes - BS; ++i)
280  {
281  last[i] ^= last[i + BS];
282  last[i + BS] ^= last[i];
283  last[i] ^= last[i + BS];
284  }
285 
286  xor_buf(last, tweak(), BS);
287  cipher().decrypt(last);
288  xor_buf(last, tweak(), BS);
289 
290  buffer += last;
291  }
292  }
293 
294 }
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:59
const BigInt & n
Definition: rsa.cpp:107
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:428
size_t output_length(size_t input_length) const override
Definition: xts.cpp:215
std::string name() const override
Definition: xts.cpp:69
BOTAN_REGISTER_BLOCK_CIPHER_MODE(SIV_Encryption, SIV_Decryption)
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:27
void update(secure_vector< byte > &blocks, size_t offset=0) override
Definition: xts.cpp:221
std::uint64_t u64bit
Definition: types.h:34
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:93
void finish(secure_vector< byte > &final_block, size_t offset=0) override
Definition: xts.cpp:250
void finish(secure_vector< byte > &final_block, size_t offset=0) override
Definition: xts.cpp:171
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
size_t parallel_bytes() const
Definition: block_cipher.h:37
void copy_mem(T *out, const T *in, size_t n)
Definition: mem_ops.h:39
Key_Length_Specification key_spec() const override
Definition: xts.cpp:84
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:79
void update(secure_vector< byte > &blocks, size_t offset=0) override
Definition: xts.cpp:142
void encrypt(const byte in[], byte out[]) const
Definition: block_cipher.h:49
virtual void encrypt_n(const byte in[], byte out[], size_t blocks) const =0
size_t round_up(size_t n, size_t align_to)
Definition: rounding.h:22
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:38
virtual size_t block_size() const =0
u64bit load_le< u64bit >(const byte in[], size_t off)
Definition: loadstor.h:219
void zeroise(std::vector< T, Alloc > &vec)
Definition: secmem.h:183
std::uint8_t byte
Definition: types.h:31