Skip to content

Commit c4582aa

Browse files
renemelieser
andcommitted
Buffered_Computation with additional conveniece API
Co-Authored-By: Philippe Lieser <philippe.lieser@rohde-schwarz.com>
1 parent 7c4634a commit c4582aa

2 files changed

Lines changed: 162 additions & 1 deletion

File tree

src/lib/base/buf_comp.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ class BOTAN_PUBLIC_API(2,0) Buffered_Computation
8080
* final result as a container of your choice.
8181
* @return a contiguous container holding the result
8282
*/
83-
template<concepts::contiguous_container T>
83+
template<typename T>
84+
requires(concepts::contiguous_container<T> &&
85+
concepts::resizable_container<T>)
8486
T final()
8587
{
8688
T output(output_length());
@@ -153,6 +155,21 @@ class BOTAN_PUBLIC_API(2,0) Buffered_Computation
153155
return final();
154156
}
155157

158+
/**
159+
* Update and finalize computation. Does the same as calling update()
160+
* and final() consecutively.
161+
* @param in the input to process as a contiguous container or string-like
162+
* @result the result of the call to final()
163+
*/
164+
template<typename OutT, typename T>
165+
requires(concepts::convertible_to<T, std::string_view> ||
166+
concepts::convertible_to<T, std::span<const uint8_t>>)
167+
OutT process(T in)
168+
{
169+
update(in);
170+
return final<OutT>();
171+
}
172+
156173
virtual ~Buffered_Computation() = default;
157174
private:
158175
/**

src/tests/test_bufcomp.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/**
2+
* (C) 2023 Jack Lloyd
3+
* 2023 Philippe Lieser - Rohde & Schwarz Cybersecurity
4+
* 2023 René Meusel - Rohde & Schwarz Cybersecurity
5+
*
6+
* Botan is released under the Simplified BSD License (see license.txt)
7+
*/
8+
9+
#include "tests.h"
10+
11+
#include <botan/buf_comp.h>
12+
#include <botan/secmem.h>
13+
#include <botan/mem_ops.h>
14+
#include <botan/strong_type.h>
15+
16+
#include <array>
17+
#include <string>
18+
#include <vector>
19+
20+
namespace Botan_Tests {
21+
22+
namespace {
23+
24+
class Test_Buf_Comp final : public Botan::Buffered_Computation
25+
{
26+
public:
27+
Test_Buf_Comp(Test::Result& res)
28+
: m_result(res)
29+
, m_counter(0) {}
30+
31+
size_t output_length() const override { return sizeof(m_counter); }
32+
33+
void add_data(const uint8_t input[], size_t length) override
34+
{
35+
if(m_result.test_eq("input length as expected", length, size_t(5)))
36+
{
37+
m_result.confirm("input[0] == 'A'", input[0] == 'A');
38+
m_result.confirm("input[0] == 'B'", input[1] == 'B');
39+
m_result.confirm("input[0] == 'C'", input[2] == 'C');
40+
m_result.confirm("input[0] == 'D'", input[3] == 'D');
41+
m_result.confirm("input[0] == 'E'", input[4] == 'E');
42+
}
43+
44+
++m_counter;
45+
}
46+
47+
void final_result(uint8_t out[]) override
48+
{
49+
const uint8_t* counter = reinterpret_cast<const uint8_t*>(&m_counter);
50+
std::copy(counter, counter + sizeof(m_counter), out);
51+
}
52+
53+
size_t counter() const { return m_counter; }
54+
55+
private:
56+
Test::Result& m_result;
57+
size_t m_counter;
58+
};
59+
60+
void check(Test::Result& result, std::span<const uint8_t> produced, size_t expected)
61+
{
62+
const uint8_t* eptr = reinterpret_cast<const uint8_t*>(&expected);
63+
result.confirm("result is correct", Botan::same_mem(produced.data(), eptr, sizeof(size_t)));
64+
}
65+
66+
using TestStdVector = Botan::Strong<std::vector<uint8_t>, struct TestStdVector_>;
67+
using TestSecureVector = Botan::Strong<Botan::secure_vector<uint8_t>, struct TestSecureVector_>;
68+
69+
Test::Result test_buffered_computation_convenience_api()
70+
{
71+
// This is mainly to test compilability of the various container
72+
// types as in and out parameters. Hence, we refrain from checking
73+
// the 'final' output everywhere.
74+
Test::Result result("Convenience API of Buffered_Computation");
75+
76+
Test_Buf_Comp t(result);
77+
78+
constexpr auto test_string = "ABCDE";
79+
const std::vector<uint8_t> test_vector = {'A', 'B', 'C', 'D', 'E'};
80+
const std::array<uint8_t, 5> test_array = {'A', 'B', 'C', 'D', 'E'};
81+
const TestStdVector test_strong_type(test_vector);
82+
83+
Botan::secure_vector<uint8_t> out_sv;
84+
std::vector<uint8_t> out_vec;
85+
std::array<uint8_t, sizeof(std::size_t)> out_arr;
86+
TestSecureVector out_strong_type;
87+
88+
// update with basic string-ish types
89+
t.update("ABCDE");
90+
t.update(test_string);
91+
t.update(std::string(test_string));
92+
93+
// update with container types
94+
t.update(test_vector);
95+
t.update(test_array);
96+
t.update(test_strong_type);
97+
98+
// final returning result
99+
out_sv = t.final();
100+
out_vec = t.final_stdvec();
101+
out_strong_type = t.final<TestSecureVector>();
102+
103+
// final using out param
104+
t.final(out_sv);
105+
t.final(out_arr);
106+
t.final(out_strong_type);
107+
108+
check(result, out_strong_type, 6);
109+
110+
// test resizing of final out param
111+
out_vec.resize(0);
112+
t.final(out_vec);
113+
out_vec.resize(t.output_length()*2);
114+
t.final(out_vec);
115+
result.test_int_eq("out vector is resized", out_vec.size(), t.output_length());
116+
117+
check(result, out_vec, 6);
118+
119+
// process with basic string-ish types as input
120+
out_sv = t.process(test_string);
121+
out_sv = t.process(std::string(test_string));
122+
123+
check(result, out_sv, 8);
124+
125+
// process with container types as input
126+
out_sv = t.process(test_vector);
127+
out_sv = t.process(test_array);
128+
129+
check(result, out_sv, 10);
130+
131+
// process with specific in and out type
132+
out_vec = t.process<std::vector<uint8_t>>(test_vector);
133+
const auto out_strong_sec_vec = t.process<TestSecureVector>(test_vector);
134+
135+
check(result, out_strong_sec_vec, 12);
136+
137+
return result;
138+
}
139+
140+
BOTAN_REGISTER_TEST_FN("base", "bufcomp_base_api", test_buffered_computation_convenience_api);
141+
142+
}
143+
144+
}

0 commit comments

Comments
 (0)