1 /*
2 * XTS Mode
3 * (C) 2009 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/xts.h>
9 #include <botan/internal/xor_buf.h>
10 #include <algorithm>
11 #include <stdexcept>
12 
13 namespace Botan {
14 
15 namespace {
16 
poly_double(byte tweak[],size_t size)17 void poly_double(byte tweak[], size_t size)
18    {
19    const byte polynomial = (size == 16) ? 0x87 : 0x1B;
20 
21    byte carry = 0;
22    for(size_t i = 0; i != size; ++i)
23       {
24       byte carry2 = (tweak[i] >> 7);
25       tweak[i] = (tweak[i] << 1) | carry;
26       carry = carry2;
27       }
28 
29    if(carry)
30       tweak[0] ^= polynomial;
31    }
32 
33 /* XTS needs to process at least 2 blocks in parallel
34    because block_size+1 bytes are needed at the end
35 */
xts_parallelism(BlockCipher * cipher)36 size_t xts_parallelism(BlockCipher* cipher)
37    {
38    return std::max<size_t>(cipher->parallel_bytes(),
39                            2 * cipher->block_size());
40    }
41 
42 }
43 
44 /*
45 * XTS_Encryption constructor
46 */
XTS_Encryption(BlockCipher * ciph)47 XTS_Encryption::XTS_Encryption(BlockCipher* ciph) :
48    Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
49    cipher(ciph)
50    {
51    if(cipher->block_size() != 8 && cipher->block_size() != 16)
52       throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
53 
54    cipher2 = cipher->clone();
55    tweak.resize(buffered_block_size());
56    }
57 
58 /*
59 * XTS_Encryption constructor
60 */
XTS_Encryption(BlockCipher * ciph,const SymmetricKey & key,const InitializationVector & iv)61 XTS_Encryption::XTS_Encryption(BlockCipher* ciph,
62                                const SymmetricKey& key,
63                                const InitializationVector& iv) :
64    Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
65    cipher(ciph)
66    {
67    if(cipher->block_size() != 8 && cipher->block_size() != 16)
68        throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
69 
70    cipher2 = cipher->clone();
71    tweak.resize(buffered_block_size());
72 
73    set_key(key);
74    set_iv(iv);
75    }
76 
77 /*
78 * Return the name
79 */
name() const80 std::string XTS_Encryption::name() const
81    {
82    return (cipher->name() + "/XTS");
83    }
84 
85 /*
86 * Set new tweak
87 */
set_iv(const InitializationVector & iv)88 void XTS_Encryption::set_iv(const InitializationVector& iv)
89    {
90    if(!valid_iv_length(iv.length()))
91       throw Invalid_IV_Length(name(), iv.length());
92 
93    const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
94 
95    tweak.copy(iv.begin(), iv.length());
96    cipher2->encrypt(tweak);
97 
98    for(size_t i = 1; i < blocks_in_tweak; ++i)
99       {
100       tweak.copy(i*cipher->block_size(),
101                  &tweak[(i-1)*cipher->block_size()],
102                  cipher->block_size());
103 
104       poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
105       }
106    }
107 
set_key(const SymmetricKey & key)108 void XTS_Encryption::set_key(const SymmetricKey& key)
109    {
110    size_t key_half = key.length() / 2;
111 
112    if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
113       throw Invalid_Key_Length(name(), key.length());
114 
115    cipher->set_key(key.begin(), key_half);
116    cipher2->set_key(key.begin() + key_half, key_half);
117    }
118 
119 /*
120 * Encrypt in XTS mode
121 */
write(const byte input[],size_t length)122 void XTS_Encryption::write(const byte input[], size_t length)
123    {
124    Buffered_Filter::write(input, length);
125    }
126 /*
127 * Finish encrypting in XTS mode
128 */
end_msg()129 void XTS_Encryption::end_msg()
130    {
131    Buffered_Filter::end_msg();
132    }
133 
buffered_block(const byte input[],size_t length)134 void XTS_Encryption::buffered_block(const byte input[], size_t length)
135    {
136    const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
137    size_t blocks = length / cipher->block_size();
138 
139    SecureVector<byte> temp(tweak.size());
140 
141    while(blocks)
142       {
143       size_t to_proc = std::min(blocks, blocks_in_tweak);
144       size_t to_proc_bytes = to_proc * cipher->block_size();
145 
146       xor_buf(temp, input, tweak, to_proc_bytes);
147 
148       cipher->encrypt_n(&temp[0], &temp[0], to_proc);
149 
150       xor_buf(temp, tweak, to_proc_bytes);
151 
152       send(temp, to_proc_bytes);
153 
154       tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
155                  cipher->block_size());
156       poly_double(&tweak[0], cipher->block_size());
157 
158       for(size_t i = 1; i < blocks_in_tweak; ++i)
159          {
160          tweak.copy(i*cipher->block_size(),
161                     &tweak[(i-1)*cipher->block_size()],
162                     cipher->block_size());
163 
164          poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
165          }
166 
167       input += to_proc * cipher->block_size();
168       blocks -= to_proc;
169       }
170    }
171 
172 /*
173 * Finish encrypting in XTS mode
174 */
buffered_final(const byte input[],size_t length)175 void XTS_Encryption::buffered_final(const byte input[], size_t length)
176    {
177    if(length <= cipher->block_size())
178       throw Encoding_Error("XTS_Encryption: insufficient data to encrypt");
179 
180    if(length % cipher->block_size() == 0)
181       {
182       buffered_block(input, length);
183       }
184    else
185       { // steal ciphertext
186 
187       size_t leftover_blocks =
188          ((length / cipher->block_size()) - 1) * cipher->block_size();
189 
190       buffered_block(input, leftover_blocks);
191 
192       input += leftover_blocks;
193       length -= leftover_blocks;
194 
195       SecureVector<byte> temp(input, length);
196 
197       xor_buf(temp, tweak, cipher->block_size());
198       cipher->encrypt(temp);
199       xor_buf(temp, tweak, cipher->block_size());
200 
201       poly_double(&tweak[0], cipher->block_size());
202 
203       for(size_t i = 0; i != length - cipher->block_size(); ++i)
204          std::swap(temp[i], temp[i + cipher->block_size()]);
205 
206       xor_buf(temp, tweak, cipher->block_size());
207       cipher->encrypt(temp);
208       xor_buf(temp, tweak, cipher->block_size());
209 
210       send(temp, temp.size());
211       }
212 
213    buffer_reset();
214    }
215 
216 /*
217 * XTS_Decryption constructor
218 */
XTS_Decryption(BlockCipher * ciph)219 XTS_Decryption::XTS_Decryption(BlockCipher* ciph) :
220    Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
221    cipher(ciph)
222    {
223    if(cipher->block_size() != 8 && cipher->block_size() != 16)
224        throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
225 
226    cipher2 = ciph->clone();
227    tweak.resize(buffered_block_size());
228    }
229 
230 /*
231 * XTS_Decryption constructor
232 */
XTS_Decryption(BlockCipher * ciph,const SymmetricKey & key,const InitializationVector & iv)233 XTS_Decryption::XTS_Decryption(BlockCipher* ciph,
234                                const SymmetricKey& key,
235                                const InitializationVector& iv) :
236    Buffered_Filter(xts_parallelism(ciph), ciph->block_size() + 1),
237    cipher(ciph)
238    {
239    if(cipher->block_size() != 8 && cipher->block_size() != 16)
240        throw std::invalid_argument("Bad cipher for XTS: " + cipher->name());
241 
242    cipher2 = ciph->clone();
243    tweak.resize(buffered_block_size());
244 
245    set_key(key);
246    set_iv(iv);
247    }
248 
249 /*
250 * Return the name
251 */
name() const252 std::string XTS_Decryption::name() const
253    {
254    return (cipher->name() + "/XTS");
255    }
256 
257 /*
258 * Set new tweak
259 */
set_iv(const InitializationVector & iv)260 void XTS_Decryption::set_iv(const InitializationVector& iv)
261    {
262    if(!valid_iv_length(iv.length()))
263       throw Invalid_IV_Length(name(), iv.length());
264 
265    const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
266 
267    tweak.copy(iv.begin(), iv.length());
268    cipher2->encrypt(tweak);
269 
270    for(size_t i = 1; i < blocks_in_tweak; ++i)
271       {
272       tweak.copy(i*cipher->block_size(),
273                  &tweak[(i-1)*cipher->block_size()],
274                  cipher->block_size());
275 
276       poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
277       }
278    }
279 
set_key(const SymmetricKey & key)280 void XTS_Decryption::set_key(const SymmetricKey& key)
281    {
282    size_t key_half = key.length() / 2;
283 
284    if(key.length() % 2 == 1 || !cipher->valid_keylength(key_half))
285       throw Invalid_Key_Length(name(), key.length());
286 
287    cipher->set_key(key.begin(), key_half);
288    cipher2->set_key(key.begin() + key_half, key_half);
289    }
290 
291 /*
292 * Decrypt in XTS mode
293 */
write(const byte input[],size_t length)294 void XTS_Decryption::write(const byte input[], size_t length)
295    {
296    Buffered_Filter::write(input, length);
297    }
298 
299 /*
300 * Finish decrypting in XTS mode
301 */
end_msg()302 void XTS_Decryption::end_msg()
303    {
304    Buffered_Filter::end_msg();
305    }
306 
buffered_block(const byte input[],size_t input_length)307 void XTS_Decryption::buffered_block(const byte input[], size_t input_length)
308    {
309    const size_t blocks_in_tweak = tweak.size() / cipher->block_size();
310    size_t blocks = input_length / cipher->block_size();
311 
312    SecureVector<byte> temp(tweak.size());
313 
314    while(blocks)
315       {
316       size_t to_proc = std::min(blocks, blocks_in_tweak);
317       size_t to_proc_bytes = to_proc * cipher->block_size();
318 
319       xor_buf(temp, input, tweak, to_proc_bytes);
320 
321       cipher->decrypt_n(&temp[0], &temp[0], to_proc);
322 
323       xor_buf(temp, tweak, to_proc_bytes);
324 
325       send(temp, to_proc_bytes);
326 
327       tweak.copy(&tweak[(to_proc-1)*cipher->block_size()],
328                  cipher->block_size());
329       poly_double(&tweak[0], cipher->block_size());
330 
331       for(size_t i = 1; i < blocks_in_tweak; ++i)
332          {
333          tweak.copy(i*cipher->block_size(),
334                     &tweak[(i-1)*cipher->block_size()],
335                     cipher->block_size());
336 
337          poly_double(&tweak[i*cipher->block_size()], cipher->block_size());
338          }
339 
340       input += to_proc * cipher->block_size();
341       blocks -= to_proc;
342       }
343    }
344 
buffered_final(const byte input[],size_t length)345 void XTS_Decryption::buffered_final(const byte input[], size_t length)
346    {
347    if(length <= cipher->block_size())
348       throw Decoding_Error("XTS_Decryption: insufficient data to decrypt");
349 
350    if(length % cipher->block_size() == 0)
351       {
352       buffered_block(input, length);
353       }
354    else
355       {
356       size_t leftover_blocks =
357          ((length / cipher->block_size()) - 1) * cipher->block_size();
358 
359       buffered_block(input, leftover_blocks);
360 
361       input += leftover_blocks;
362       length -= leftover_blocks;
363 
364       SecureVector<byte> temp(input, length);
365       SecureVector<byte> tweak_copy(&tweak[0], cipher->block_size());
366 
367       poly_double(&tweak_copy[0], cipher->block_size());
368 
369       xor_buf(temp, tweak_copy, cipher->block_size());
370       cipher->decrypt(temp);
371       xor_buf(temp, tweak_copy, cipher->block_size());
372 
373       for(size_t i = 0; i != length - cipher->block_size(); ++i)
374          std::swap(temp[i], temp[i + cipher->block_size()]);
375 
376       xor_buf(temp, tweak, cipher->block_size());
377       cipher->decrypt(temp);
378       xor_buf(temp, tweak, cipher->block_size());
379 
380       send(temp, length);
381       }
382 
383    buffer_reset();
384    }
385 
386 }
387