Botan 3.8.1
Crypto and TLS for C&
xts.cpp
Go to the documentation of this file.
1/*
2* XTS Mode
3* (C) 2009,2013 Jack Lloyd
4* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
5*
6* Botan is released under the Simplified BSD License (see license.txt)
7*/
8
9#include <botan/internal/xts.h>
10
11#include <botan/mem_ops.h>
12#include <botan/internal/fmt.h>
13#include <botan/internal/poly_dbl.h>
14
15namespace Botan {
16
17XTS_Mode::XTS_Mode(std::unique_ptr<BlockCipher> cipher) :
18 m_cipher(std::move(cipher)),
19 m_cipher_block_size(m_cipher->block_size()),
20 m_cipher_parallelism(m_cipher->parallel_bytes()),
21 m_tweak_blocks(m_cipher_parallelism / m_cipher_block_size) {
22 if(poly_double_supported_size(m_cipher_block_size) == false) {
23 throw Invalid_Argument(fmt("Cannot use {} with XTS", m_cipher->name()));
24 }
25
26 m_tweak_cipher = m_cipher->new_object();
27}
28
30 m_cipher->clear();
31 m_tweak_cipher->clear();
32 reset();
33}
34
36 return m_cipher_block_size;
37}
38
40 return m_cipher_parallelism;
41}
42
44 m_tweak.clear();
45}
46
47std::string XTS_Mode::name() const {
48 return cipher().name() + "/XTS";
49}
50
52 return cipher_block_size();
53}
54
58
60 return cipher_block_size();
61}
62
63bool XTS_Mode::valid_nonce_length(size_t n) const {
64 return n <= cipher_block_size();
65}
66
68 return m_cipher->has_keying_material() && m_tweak_cipher->has_keying_material();
69}
70
71void XTS_Mode::key_schedule(std::span<const uint8_t> key) {
72 const size_t key_half = key.size() / 2;
73
74 if(key.size() % 2 == 1 || !m_cipher->valid_keylength(key_half)) {
75 throw Invalid_Key_Length(name(), key.size());
76 }
77
78 m_cipher->set_key(key.first(key_half));
79 m_tweak_cipher->set_key(key.last(key_half));
80}
81
82void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
83 if(!valid_nonce_length(nonce_len)) {
84 throw Invalid_IV_Length(name(), nonce_len);
85 }
86
87 m_tweak.resize(m_cipher_parallelism);
88 clear_mem(m_tweak.data(), m_tweak.size());
89 copy_mem(m_tweak.data(), nonce, nonce_len);
90 m_tweak_cipher->encrypt(m_tweak.data());
91
92 update_tweak(0);
93}
94
95void XTS_Mode::update_tweak(size_t which) {
96 const size_t BS = m_tweak_cipher->block_size();
97
98 if(which > 0) {
99 poly_double_n_le(m_tweak.data(), &m_tweak[(which - 1) * BS], BS);
100 }
101
102 const size_t blocks_in_tweak = tweak_blocks();
103
104 xts_update_tweak_block(m_tweak.data(), BS, blocks_in_tweak);
105}
106
107size_t XTS_Encryption::output_length(size_t input_length) const {
108 return input_length;
109}
110
111size_t XTS_Encryption::process_msg(uint8_t buf[], size_t sz) {
113 const size_t BS = cipher_block_size();
114
115 BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
116 size_t blocks = sz / BS;
117
118 const size_t blocks_in_tweak = tweak_blocks();
119
120 while(blocks) {
121 const size_t to_proc = std::min(blocks, blocks_in_tweak);
122 const size_t proc_bytes = to_proc * BS;
123
124 xor_buf(buf, tweak(), proc_bytes);
125 cipher().encrypt_n(buf, buf, to_proc);
126 xor_buf(buf, tweak(), proc_bytes);
127
128 buf += proc_bytes;
129 blocks -= to_proc;
130
131 update_tweak(to_proc);
132 }
133
134 return sz;
135}
136
137void XTS_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
138 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
139 const size_t sz = buffer.size() - offset;
140 uint8_t* buf = buffer.data() + offset;
141
142 BOTAN_ARG_CHECK(sz >= minimum_final_size(), "missing sufficient final input in XTS encrypt");
143
144 const size_t BS = cipher_block_size();
145
146 if(sz % BS == 0) {
147 update(buffer, offset);
148 } else {
149 // steal ciphertext
150 const size_t full_blocks = ((sz / BS) - 1) * BS;
151 const size_t final_bytes = sz - full_blocks;
152 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
153
154 secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
155 buffer.resize(full_blocks + offset);
156 update(buffer, offset);
157
158 xor_buf(last, tweak(), BS);
159 cipher().encrypt(last);
160 xor_buf(last, tweak(), BS);
161
162 for(size_t i = 0; i != final_bytes - BS; ++i) {
163 last[i] ^= last[i + BS];
164 last[i + BS] ^= last[i];
165 last[i] ^= last[i + BS];
166 }
167
168 xor_buf(last, tweak() + BS, BS);
169 cipher().encrypt(last);
170 xor_buf(last, tweak() + BS, BS);
171
172 buffer += last;
173 }
174}
175
176size_t XTS_Decryption::output_length(size_t input_length) const {
177 return input_length;
178}
179
180size_t XTS_Decryption::process_msg(uint8_t buf[], size_t sz) {
182 const size_t BS = cipher_block_size();
183
184 BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
185 size_t blocks = sz / BS;
186
187 const size_t blocks_in_tweak = tweak_blocks();
188
189 while(blocks) {
190 const size_t to_proc = std::min(blocks, blocks_in_tweak);
191 const size_t proc_bytes = to_proc * BS;
192
193 xor_buf(buf, tweak(), proc_bytes);
194 cipher().decrypt_n(buf, buf, to_proc);
195 xor_buf(buf, tweak(), proc_bytes);
196
197 buf += proc_bytes;
198 blocks -= to_proc;
199
200 update_tweak(to_proc);
201 }
202
203 return sz;
204}
205
206void XTS_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
207 BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
208 const size_t sz = buffer.size() - offset;
209 uint8_t* buf = buffer.data() + offset;
210
211 BOTAN_ARG_CHECK(sz >= minimum_final_size(), "missing sufficient final input in XTS decrypt");
212
213 const size_t BS = cipher_block_size();
214
215 if(sz % BS == 0) {
216 update(buffer, offset);
217 } else {
218 // steal ciphertext
219 const size_t full_blocks = ((sz / BS) - 1) * BS;
220 const size_t final_bytes = sz - full_blocks;
221 BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
222
223 secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
224 buffer.resize(full_blocks + offset);
225 update(buffer, offset);
226
227 xor_buf(last, tweak() + BS, BS);
228 cipher().decrypt(last);
229 xor_buf(last, tweak() + BS, BS);
230
231 for(size_t i = 0; i != final_bytes - BS; ++i) {
232 last[i] ^= last[i + BS];
233 last[i + BS] ^= last[i];
234 last[i] ^= last[i + BS];
235 }
236
237 xor_buf(last, tweak(), BS);
238 cipher().decrypt(last);
239 xor_buf(last, tweak(), BS);
240
241 buffer += last;
242 }
243}
244
245} // namespace Botan
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:43
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:31
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:52
void encrypt(const uint8_t in[], uint8_t out[]) const
void decrypt(const uint8_t in[], uint8_t out[]) const
virtual void decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const =0
virtual void encrypt_n(const uint8_t in[], uint8_t out[], size_t blocks) const =0
void update(T &buffer, size_t offset=0)
Key_Length_Specification multiple(size_t n) const
Definition sym_algo.h:68
virtual std::string name() const =0
virtual Key_Length_Specification key_spec() const =0
size_t output_length(size_t input_length) const override
Definition xts.cpp:176
size_t output_length(size_t input_length) const override
Definition xts.cpp:107
void reset() final
Definition xts.cpp:43
const uint8_t * tweak() const
Definition xts.h:45
size_t ideal_granularity() const final
Definition xts.cpp:39
std::string name() const final
Definition xts.cpp:47
size_t default_nonce_length() const final
Definition xts.cpp:59
size_t cipher_block_size() const
Definition xts.h:55
size_t update_granularity() const final
Definition xts.cpp:35
bool has_keying_material() const final
Definition xts.cpp:67
void clear() final
Definition xts.cpp:29
XTS_Mode(std::unique_ptr< BlockCipher > cipher)
Definition xts.cpp:17
const BlockCipher & cipher() const
Definition xts.h:51
size_t tweak_blocks() const
Definition xts.h:49
Key_Length_Specification key_spec() const final
Definition xts.cpp:55
void update_tweak(size_t last_used)
Definition xts.cpp:95
bool tweak_set() const
Definition xts.h:47
bool valid_nonce_length(size_t n) const final
Definition xts.cpp:63
size_t minimum_final_size() const final
Definition xts.cpp:51
void xts_update_tweak_block(uint8_t tweak[], size_t BS, size_t blocks_in_tweak)
Definition poly_dbl.cpp:119
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
void poly_double_n_le(uint8_t out[], const uint8_t in[], size_t n)
Definition poly_dbl.cpp:100
constexpr void xor_buf(ranges::contiguous_output_range< uint8_t > auto &&out, ranges::contiguous_range< uint8_t > auto &&in)
Definition mem_ops.h:344
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:65
bool poly_double_supported_size(size_t n)
Definition poly_dbl.h:22
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:149
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:123