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