• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 13274522654

11 Feb 2025 11:26PM UTC coverage: 91.645% (-0.007%) from 91.652%
13274522654

push

github

web-flow
Merge pull request #4647 from randombit/jack/internal-assert-and-mem-ops

Avoid using mem_ops.h or assert.h in public headers

94854 of 103501 relevant lines covered (91.65%)

11334975.77 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.63
/src/lib/modes/xts/xts.cpp
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

15
namespace Botan {
16

17
XTS_Mode::XTS_Mode(std::unique_ptr<BlockCipher> cipher) :
4,175✔
18
      m_cipher(std::move(cipher)),
4,175✔
19
      m_cipher_block_size(m_cipher->block_size()),
4,175✔
20
      m_cipher_parallelism(m_cipher->parallel_bytes()),
4,175✔
21
      m_tweak_blocks(m_cipher_parallelism / m_cipher_block_size) {
4,175✔
22
   if(poly_double_supported_size(m_cipher_block_size) == false) {
4,175✔
23
      throw Invalid_Argument(fmt("Cannot use {} with XTS", m_cipher->name()));
×
24
   }
25

26
   m_tweak_cipher = m_cipher->new_object();
4,175✔
27
}
4,175✔
28

29
void XTS_Mode::clear() {
1,670✔
30
   m_cipher->clear();
1,670✔
31
   m_tweak_cipher->clear();
1,670✔
32
   reset();
3,340✔
33
}
1,670✔
34

35
size_t XTS_Mode::update_granularity() const {
5,845✔
36
   return m_cipher_block_size;
5,845✔
37
}
38

39
size_t XTS_Mode::ideal_granularity() const {
5,010✔
40
   return m_cipher_parallelism;
5,010✔
41
}
42

43
void XTS_Mode::reset() {
5,010✔
44
   m_tweak.clear();
5,010✔
45
}
3,340✔
46

47
std::string XTS_Mode::name() const {
3,340✔
48
   return cipher().name() + "/XTS";
6,680✔
49
}
50

51
size_t XTS_Mode::minimum_final_size() const {
14,258✔
52
   return cipher_block_size();
14,258✔
53
}
54

55
Key_Length_Specification XTS_Mode::key_spec() const {
5,010✔
56
   return cipher().key_spec().multiple(2);
5,010✔
57
}
58

59
size_t XTS_Mode::default_nonce_length() const {
1,670✔
60
   return cipher_block_size();
1,670✔
61
}
62

63
bool XTS_Mode::valid_nonce_length(size_t n) const {
15,928✔
64
   return n <= cipher_block_size();
15,928✔
65
}
66

67
bool XTS_Mode::has_keying_material() const {
5,010✔
68
   return m_cipher->has_keying_material() && m_tweak_cipher->has_keying_material();
5,010✔
69
}
70

71
void XTS_Mode::key_schedule(std::span<const uint8_t> key) {
5,010✔
72
   const size_t key_half = key.size() / 2;
5,010✔
73

74
   if(key.size() % 2 == 1 || !m_cipher->valid_keylength(key_half)) {
5,010✔
75
      throw Invalid_Key_Length(name(), key.size());
×
76
   }
77

78
   m_cipher->set_key(key.first(key_half));
5,010✔
79
   m_tweak_cipher->set_key(key.last(key_half));
5,010✔
80
}
5,010✔
81

82
void XTS_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) {
12,588✔
83
   if(!valid_nonce_length(nonce_len)) {
12,588✔
84
      throw Invalid_IV_Length(name(), nonce_len);
3,340✔
85
   }
86

87
   m_tweak.resize(m_cipher_parallelism);
10,918✔
88
   clear_mem(m_tweak.data(), m_tweak.size());
10,918✔
89
   copy_mem(m_tweak.data(), nonce, nonce_len);
10,918✔
90
   m_tweak_cipher->encrypt(m_tweak.data());
10,918✔
91

92
   update_tweak(0);
10,918✔
93
}
10,918✔
94

95
void XTS_Mode::update_tweak(size_t which) {
34,700✔
96
   const size_t BS = m_tweak_cipher->block_size();
34,700✔
97

98
   if(which > 0) {
34,700✔
99
      poly_double_n_le(m_tweak.data(), &m_tweak[(which - 1) * BS], BS);
23,782✔
100
   }
101

102
   const size_t blocks_in_tweak = tweak_blocks();
34,700✔
103

104
   xts_update_tweak_block(m_tweak.data(), BS, blocks_in_tweak);
34,700✔
105
}
34,700✔
106

107
size_t XTS_Encryption::output_length(size_t input_length) const {
835✔
108
   return input_length;
835✔
109
}
110

111
size_t XTS_Encryption::process_msg(uint8_t buf[], size_t sz) {
16,715✔
112
   BOTAN_STATE_CHECK(tweak_set());
16,715✔
113
   const size_t BS = cipher_block_size();
11,705✔
114

115
   BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
11,705✔
116
   size_t blocks = sz / BS;
11,705✔
117

118
   const size_t blocks_in_tweak = tweak_blocks();
11,705✔
119

120
   while(blocks) {
23,596✔
121
      const size_t to_proc = std::min(blocks, blocks_in_tweak);
11,891✔
122
      const size_t proc_bytes = to_proc * BS;
11,891✔
123

124
      xor_buf(buf, tweak(), proc_bytes);
11,891✔
125
      cipher().encrypt_n(buf, buf, to_proc);
11,891✔
126
      xor_buf(buf, tweak(), proc_bytes);
11,891✔
127

128
      buf += proc_bytes;
11,891✔
129
      blocks -= to_proc;
11,891✔
130

131
      update_tweak(to_proc);
11,891✔
132
   }
133

134
   return sz;
11,705✔
135
}
136

137
void XTS_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
6,294✔
138
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
6,294✔
139
   const size_t sz = buffer.size() - offset;
6,294✔
140
   uint8_t* buf = buffer.data() + offset;
6,294✔
141

142
   BOTAN_ARG_CHECK(sz >= minimum_final_size(), "missing sufficient final input in XTS encrypt");
6,294✔
143

144
   const size_t BS = cipher_block_size();
6,294✔
145

146
   if(sz % BS == 0) {
6,294✔
147
      update(buffer, offset);
2,862✔
148
   } else {
149
      // steal ciphertext
150
      const size_t full_blocks = ((sz / BS) - 1) * BS;
3,432✔
151
      const size_t final_bytes = sz - full_blocks;
3,432✔
152
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
3,432✔
153

154
      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
3,432✔
155
      buffer.resize(full_blocks + offset);
3,432✔
156
      update(buffer, offset);
3,432✔
157

158
      xor_buf(last, tweak(), BS);
3,432✔
159
      cipher().encrypt(last);
3,432✔
160
      xor_buf(last, tweak(), BS);
3,432✔
161

162
      for(size_t i = 0; i != final_bytes - BS; ++i) {
27,560✔
163
         last[i] ^= last[i + BS];
24,128✔
164
         last[i + BS] ^= last[i];
24,128✔
165
         last[i] ^= last[i + BS];
24,128✔
166
      }
167

168
      xor_buf(last, tweak() + BS, BS);
3,432✔
169
      cipher().encrypt(last);
3,432✔
170
      xor_buf(last, tweak() + BS, BS);
3,432✔
171

172
      buffer += last;
3,432✔
173
   }
3,432✔
174
}
3,789✔
175

176
size_t XTS_Decryption::output_length(size_t input_length) const {
835✔
177
   return input_length;
835✔
178
}
179

180
size_t XTS_Decryption::process_msg(uint8_t buf[], size_t sz) {
16,715✔
181
   BOTAN_STATE_CHECK(tweak_set());
16,715✔
182
   const size_t BS = cipher_block_size();
11,705✔
183

184
   BOTAN_ARG_CHECK(sz % BS == 0, "Input is not full blocks");
11,705✔
185
   size_t blocks = sz / BS;
11,705✔
186

187
   const size_t blocks_in_tweak = tweak_blocks();
11,705✔
188

189
   while(blocks) {
23,596✔
190
      const size_t to_proc = std::min(blocks, blocks_in_tweak);
11,891✔
191
      const size_t proc_bytes = to_proc * BS;
11,891✔
192

193
      xor_buf(buf, tweak(), proc_bytes);
11,891✔
194
      cipher().decrypt_n(buf, buf, to_proc);
11,891✔
195
      xor_buf(buf, tweak(), proc_bytes);
11,891✔
196

197
      buf += proc_bytes;
11,891✔
198
      blocks -= to_proc;
11,891✔
199

200
      update_tweak(to_proc);
11,891✔
201
   }
202

203
   return sz;
11,705✔
204
}
205

206
void XTS_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
6,294✔
207
   BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
6,294✔
208
   const size_t sz = buffer.size() - offset;
6,294✔
209
   uint8_t* buf = buffer.data() + offset;
6,294✔
210

211
   BOTAN_ARG_CHECK(sz >= minimum_final_size(), "missing sufficient final input in XTS decrypt");
6,294✔
212

213
   const size_t BS = cipher_block_size();
6,294✔
214

215
   if(sz % BS == 0) {
6,294✔
216
      update(buffer, offset);
2,862✔
217
   } else {
218
      // steal ciphertext
219
      const size_t full_blocks = ((sz / BS) - 1) * BS;
3,432✔
220
      const size_t final_bytes = sz - full_blocks;
3,432✔
221
      BOTAN_ASSERT(final_bytes > BS && final_bytes < 2 * BS, "Left over size in expected range");
3,432✔
222

223
      secure_vector<uint8_t> last(buf + full_blocks, buf + full_blocks + final_bytes);
3,432✔
224
      buffer.resize(full_blocks + offset);
3,432✔
225
      update(buffer, offset);
3,432✔
226

227
      xor_buf(last, tweak() + BS, BS);
3,432✔
228
      cipher().decrypt(last);
3,432✔
229
      xor_buf(last, tweak() + BS, BS);
3,432✔
230

231
      for(size_t i = 0; i != final_bytes - BS; ++i) {
27,560✔
232
         last[i] ^= last[i + BS];
24,128✔
233
         last[i + BS] ^= last[i];
24,128✔
234
         last[i] ^= last[i + BS];
24,128✔
235
      }
236

237
      xor_buf(last, tweak(), BS);
3,432✔
238
      cipher().decrypt(last);
3,432✔
239
      xor_buf(last, tweak(), BS);
3,432✔
240

241
      buffer += last;
3,432✔
242
   }
3,432✔
243
}
3,789✔
244

245
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc