Skip to content

Commit a93a6f1

Browse files
committed
WIP
1 parent 0ffb30b commit a93a6f1

File tree

24 files changed

+649
-488
lines changed

24 files changed

+649
-488
lines changed

src/fuzzer/mode_padding.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ void fuzz(std::span<const uint8_t> in) {
161161
FUZZER_ASSERT_EQUAL(ct_esp, ref_esp);
162162
}
163163

164-
const uint16_t ct_cbc = Botan::TLS::check_tls_cbc_padding(in.data(), len);
164+
const uint16_t ct_cbc = Botan::TLS::check_tls_cbc_padding(in);
165165
const uint16_t ref_cbc = ref_tls_cbc_unpad(in);
166166
FUZZER_ASSERT_EQUAL(ct_cbc, ref_cbc);
167167
}

src/lib/modes/aead/ccm/ccm.cpp

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <botan/internal/ct_utils.h>
1212
#include <botan/internal/fmt.h>
1313
#include <botan/internal/loadstor.h>
14+
#include <botan/internal/stl_util.h>
1415

1516
namespace Botan {
1617

@@ -168,24 +169,28 @@ secure_vector<uint8_t> CCM_Mode::format_c0() {
168169
return C;
169170
}
170171

171-
void CCM_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
172-
BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
172+
size_t CCM_Encryption::finish_msg(std::span<uint8_t> buffer, size_t input_bytes) {
173+
const auto tag_length = tag_size();
174+
const auto& buffered = msg_buf();
173175

174-
buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
176+
BOTAN_ASSERT_NOMSG(buffered.size() + input_bytes + tag_length == buffer.size());
175177

176-
const size_t sz = buffer.size() - offset;
177-
uint8_t* buf = buffer.data() + offset;
178+
const auto entire_payload = buffer.first(buffered.size() + input_bytes);
179+
const auto tag = buffer.last(tag_length);
178180

179181
const secure_vector<uint8_t>& ad = ad_buf();
180182
BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
181183

182184
const BlockCipher& E = cipher();
183185

186+
// TODO: consider using std::array<> for all those block-size'ed buffers
187+
// (this requires adapting more helper functions like `format_b0`, ...)
184188
secure_vector<uint8_t> T(CCM_BS);
185-
E.encrypt(format_b0(sz), T);
189+
E.encrypt(format_b0(entire_payload.size()), T);
186190

187-
for(size_t i = 0; i != ad.size(); i += CCM_BS) {
188-
xor_buf(T.data(), &ad[i], CCM_BS);
191+
BufferSlicer ad_bs(ad);
192+
while(!ad_bs.empty()) {
193+
xor_buf(T, ad_bs.take(CCM_BS));
189194
E.encrypt(T);
190195
}
191196

@@ -196,45 +201,56 @@ void CCM_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
196201

197202
secure_vector<uint8_t> X(CCM_BS);
198203

199-
const uint8_t* buf_end = &buf[sz];
204+
// copy all buffered input into the in/out buffer if needed
205+
if(!buffered.empty()) {
206+
copy_mem(entire_payload.last(input_bytes), entire_payload.first(input_bytes));
207+
copy_mem(entire_payload.first(buffered.size()), buffered);
208+
}
209+
210+
// TODO: Use BufferTransformer, once it is available
211+
// See https://github.com/randombit/botan/pull/4151
212+
BufferSlicer payload_slicer(entire_payload);
213+
BufferStuffer payload_stuffer(entire_payload);
200214

201-
while(buf != buf_end) {
202-
const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
215+
while(!payload_slicer.empty()) {
216+
const size_t to_proc = std::min<size_t>(CCM_BS, payload_slicer.remaining());
217+
const auto in_chunk = payload_slicer.take(to_proc);
218+
const auto out_chunk = payload_stuffer.next(to_proc);
203219

204-
xor_buf(T.data(), buf, to_proc);
220+
xor_buf(std::span{T}.first(in_chunk.size()), in_chunk);
205221
E.encrypt(T);
206222

207223
E.encrypt(C, X);
208-
xor_buf(buf, X.data(), to_proc);
224+
xor_buf(out_chunk, std::span{X}.first(out_chunk.size()));
209225
inc(C);
210-
211-
buf += to_proc;
212226
}
213227

214228
T ^= S0;
215229

216-
buffer += std::make_pair(T.data(), tag_size());
230+
BOTAN_DEBUG_ASSERT(tag.size() <= T.size());
231+
copy_mem(tag, std::span{T}.first(tag.size()));
217232

218233
reset();
219-
}
220234

221-
void CCM_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
222-
BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
235+
return buffer.size();
236+
}
223237

224-
buffer.insert(buffer.begin() + offset, msg_buf().begin(), msg_buf().end());
238+
size_t CCM_Decryption::finish_msg(std::span<uint8_t> buffer, size_t input_bytes) {
239+
const auto tag_length = tag_size();
240+
const auto& buffered = msg_buf();
225241

226-
const size_t sz = buffer.size() - offset;
227-
uint8_t* buf = buffer.data() + offset;
242+
BOTAN_ASSERT_NOMSG(buffered.size() + input_bytes == buffer.size());
228243

229-
BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
244+
const auto entire_payload = buffer.first(buffer.size() - tag_length);
245+
const auto tag = buffer.last(tag_length);
230246

231247
const secure_vector<uint8_t>& ad = ad_buf();
232248
BOTAN_ARG_CHECK(ad.size() % CCM_BS == 0, "AD is block size multiple");
233249

234250
const BlockCipher& E = cipher();
235251

236252
secure_vector<uint8_t> T(CCM_BS);
237-
E.encrypt(format_b0(sz - tag_size()), T);
253+
E.encrypt(format_b0(entire_payload.size()), T);
238254

239255
for(size_t i = 0; i != ad.size(); i += CCM_BS) {
240256
xor_buf(T.data(), &ad[i], CCM_BS);
@@ -249,30 +265,39 @@ void CCM_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
249265

250266
secure_vector<uint8_t> X(CCM_BS);
251267

252-
const uint8_t* buf_end = &buf[sz - tag_size()];
268+
// copy all buffered input into the in/out buffer if needed
269+
if(!buffered.empty()) {
270+
copy_mem(buffer.last(input_bytes), buffer.first(input_bytes));
271+
copy_mem(buffer.first(buffered.size()), buffered);
272+
}
273+
274+
// TODO: Use BufferTransformer, once it is available
275+
// See https://github.com/randombit/botan/pull/4151
276+
BufferSlicer payload_slicer(entire_payload);
277+
BufferStuffer payload_stuffer(entire_payload);
253278

254-
while(buf != buf_end) {
255-
const size_t to_proc = std::min<size_t>(CCM_BS, buf_end - buf);
279+
while(!payload_slicer.empty()) {
280+
const size_t to_proc = std::min<size_t>(CCM_BS, payload_slicer.remaining());
281+
const auto in_chunk = payload_slicer.take(to_proc);
282+
const auto out_chunk = payload_stuffer.next(to_proc);
256283

257284
E.encrypt(C, X);
258-
xor_buf(buf, X.data(), to_proc);
285+
xor_buf(out_chunk, std::span{X}.first(out_chunk.size()));
259286
inc(C);
260287

261-
xor_buf(T.data(), buf, to_proc);
288+
xor_buf(std::span{T}.first(in_chunk.size()), in_chunk);
262289
E.encrypt(T);
263-
264-
buf += to_proc;
265290
}
266291

267292
T ^= S0;
268293

269-
if(!CT::is_equal(T.data(), buf_end, tag_size()).as_bool()) {
294+
if(!CT::is_equal(T.data(), tag.data(), tag.size()).as_bool()) {
270295
throw Invalid_Authentication_Tag("CCM tag check failed");
271296
}
272297

273-
buffer.resize(buffer.size() - tag_size());
274-
275298
reset();
299+
300+
return entire_payload.size();
276301
}
277302

278303
} // namespace Botan

src/lib/modes/aead/ccm/ccm.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ class CCM_Mode : public AEAD_Mode {
6363

6464
secure_vector<uint8_t>& msg_buf() { return m_msg_buf; }
6565

66+
const secure_vector<uint8_t>& msg_buf() const { return m_msg_buf; }
67+
6668
secure_vector<uint8_t> format_b0(size_t msg_size);
6769
secure_vector<uint8_t> format_c0();
6870

@@ -96,10 +98,14 @@ class CCM_Encryption final : public CCM_Mode {
9698

9799
size_t output_length(size_t input_length) const override { return input_length + tag_size(); }
98100

101+
size_t bytes_needed_for_finalization(size_t final_input_length) const override {
102+
return output_length(msg_buf().size() + final_input_length);
103+
}
104+
99105
size_t minimum_final_size() const override { return 0; }
100106

101107
private:
102-
void finish_msg(secure_vector<uint8_t>& final_block, size_t offset = 0) override;
108+
size_t finish_msg(std::span<uint8_t> final_block, size_t input_bytes) override;
103109
};
104110

105111
/**
@@ -122,10 +128,15 @@ class CCM_Decryption final : public CCM_Mode {
122128
return input_length - tag_size();
123129
}
124130

131+
size_t bytes_needed_for_finalization(size_t final_input_length) const override {
132+
BOTAN_ARG_CHECK(final_input_length >= tag_size(), "Sufficient input");
133+
return msg_buf().size() + final_input_length;
134+
}
135+
125136
size_t minimum_final_size() const override { return tag_size(); }
126137

127138
private:
128-
void finish_msg(secure_vector<uint8_t>& final_block, size_t offset = 0) override;
139+
size_t finish_msg(std::span<uint8_t> final_block, size_t input_bytes) override;
129140
};
130141

131142
} // namespace Botan

src/lib/modes/aead/chacha20poly1305/chacha20poly1305.cpp

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -102,21 +102,29 @@ size_t ChaCha20Poly1305_Encryption::process_msg(uint8_t buf[], size_t sz) {
102102
return sz;
103103
}
104104

105-
void ChaCha20Poly1305_Encryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
106-
update(buffer, offset);
105+
size_t ChaCha20Poly1305_Encryption::finish_msg(std::span<uint8_t> buffer, size_t input_bytes) {
106+
const auto tag_length = tag_size();
107+
108+
BOTAN_ASSERT_NOMSG(input_bytes + tag_length == buffer.size());
109+
110+
const auto payload = buffer.first(input_bytes);
111+
const auto tag = buffer.last(tag_length);
112+
113+
process(payload);
107114
if(cfrg_version()) {
108115
if(m_ctext_len % 16) {
109-
const uint8_t zeros[16] = {0};
110-
m_poly1305->update(zeros, 16 - m_ctext_len % 16);
116+
std::array<uint8_t, 16> zeros{};
117+
m_poly1305->update(std::span{zeros}.first(16 - m_ctext_len % 16));
111118
}
112119
update_len(m_ad.size());
113120
}
114121
update_len(m_ctext_len);
115122

116-
buffer.resize(buffer.size() + tag_size());
117-
m_poly1305->final(&buffer[buffer.size() - tag_size()]);
123+
m_poly1305->final(tag);
118124
m_ctext_len = 0;
119125
m_nonce_len = 0;
126+
127+
return buffer.size();
120128
}
121129

122130
size_t ChaCha20Poly1305_Decryption::process_msg(uint8_t buf[], size_t sz) {
@@ -126,43 +134,40 @@ size_t ChaCha20Poly1305_Decryption::process_msg(uint8_t buf[], size_t sz) {
126134
return sz;
127135
}
128136

129-
void ChaCha20Poly1305_Decryption::finish_msg(secure_vector<uint8_t>& buffer, size_t offset) {
130-
BOTAN_ARG_CHECK(buffer.size() >= offset, "Offset is out of range");
131-
const size_t sz = buffer.size() - offset;
132-
uint8_t* buf = buffer.data() + offset;
137+
size_t ChaCha20Poly1305_Decryption::finish_msg(std::span<uint8_t> buffer, size_t input_bytes) {
138+
const auto tag_length = tag_size();
133139

134-
BOTAN_ARG_CHECK(sz >= tag_size(), "input did not include the tag");
140+
BOTAN_ASSERT_NOMSG(buffer.size() == input_bytes);
141+
BOTAN_ASSERT_NOMSG(buffer.size() >= tag_length);
135142

136-
const size_t remaining = sz - tag_size();
143+
const auto remaining = buffer.first(buffer.size() - tag_length);
144+
const auto tag = buffer.last(tag_length);
137145

138-
if(remaining) {
139-
m_poly1305->update(buf, remaining); // poly1305 of ciphertext
140-
m_chacha->cipher1(buf, remaining);
141-
m_ctext_len += remaining;
146+
if(!remaining.empty()) {
147+
process(remaining);
142148
}
143149

144150
if(cfrg_version()) {
145151
if(m_ctext_len % 16) {
146-
const uint8_t zeros[16] = {0};
147-
m_poly1305->update(zeros, 16 - m_ctext_len % 16);
152+
std::array<uint8_t, 16> zeros{};
153+
m_poly1305->update(std::span{zeros}.first(16 - m_ctext_len % 16));
148154
}
149155
update_len(m_ad.size());
150156
}
151157

152158
update_len(m_ctext_len);
153159

154-
uint8_t mac[16];
160+
std::array<uint8_t, 16> mac;
155161
m_poly1305->final(mac);
156162

157-
const uint8_t* included_tag = &buf[remaining];
158-
159163
m_ctext_len = 0;
160164
m_nonce_len = 0;
161165

162-
if(!CT::is_equal(mac, included_tag, tag_size()).as_bool()) {
166+
if(!CT::is_equal(mac.data(), tag.data(), tag.size()).as_bool()) {
163167
throw Invalid_Authentication_Tag("ChaCha20Poly1305 tag check failed");
164168
}
165-
buffer.resize(offset + remaining);
169+
170+
return remaining.size();
166171
}
167172

168173
} // namespace Botan

src/lib/modes/aead/chacha20poly1305/chacha20poly1305.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ class ChaCha20Poly1305_Encryption final : public ChaCha20Poly1305_Mode {
7777

7878
size_t minimum_final_size() const override { return 0; }
7979

80+
size_t bytes_needed_for_finalization(size_t final_input_length) const override {
81+
return output_length(final_input_length);
82+
}
83+
8084
private:
8185
size_t process_msg(uint8_t buf[], size_t size) override;
82-
void finish_msg(secure_vector<uint8_t>& final_block, size_t offset = 0) override;
86+
size_t finish_msg(std::span<uint8_t> final_block, size_t input_bytes) override;
8387
};
8488

8589
/**
@@ -94,9 +98,14 @@ class ChaCha20Poly1305_Decryption final : public ChaCha20Poly1305_Mode {
9498

9599
size_t minimum_final_size() const override { return tag_size(); }
96100

101+
size_t bytes_needed_for_finalization(size_t final_input_length) const override {
102+
BOTAN_ARG_CHECK(final_input_length >= tag_size(), "Sufficient input");
103+
return final_input_length;
104+
}
105+
97106
private:
98107
size_t process_msg(uint8_t buf[], size_t size) override;
99-
void finish_msg(secure_vector<uint8_t>& final_block, size_t offset = 0) override;
108+
size_t finish_msg(std::span<uint8_t> final_block, size_t input_bytes) override;
100109
};
101110

102111
} // namespace Botan

0 commit comments

Comments
 (0)