10#include <botan/internal/sp800_108.h>
12#include <botan/exceptn.h>
13#include <botan/internal/bit_ops.h>
14#include <botan/internal/fmt.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/stl_util.h>
26 constexpr static void validate_bit_lengths(
size_t counter_bits,
size_t output_length_bits) {
28 "SP.800-108 counter length may be one of {8, 16, 24, 32} only");
29 BOTAN_ARG_CHECK(output_length_bits % 8 == 0 && output_length_bits <= 32,
30 "SP.800-108 output length encoding may be one of {8, 16, 24, 32} only");
33 static CounterParams create_or_throw(
size_t output_bytes,
34 size_t output_length_bits,
36 size_t prf_output_bytes) {
39 BOTAN_ARG_CHECK(
static_cast<uint64_t
>(output_bytes) * 8 <= std::numeric_limits<uint32_t>::max(),
40 "SP.800-108 output size in bits does not fit into 32-bits");
41 const auto output_bits =
static_cast<uint32_t
>(output_bytes * 8);
42 const auto max_output_bits = (uint64_t(1) << output_length_bits) - 1;
44 "SP.800-108 output size does not fit into the requested field length");
47 const auto blocks_required =
ceil_division<uint64_t >(output_bytes, prf_output_bytes);
52 const auto max_blocks = (uint64_t(1) << counter_bits) - 1;
53 BOTAN_ARG_CHECK(blocks_required < max_blocks,
"SP.800-108 output size too large");
56 output_bits, output_length_bits / 8, counter_bits / 8,
static_cast<uint32_t
>(blocks_required));
59 template <std::invocable<std::span<const u
int8_t>, std::span<const u
int8_t>> Fn>
60 constexpr void generate_blocks(Fn fn)
const {
61 const auto outlen_encoded =
store_be(m_output_length_bits);
62 for(uint32_t counter = 1; counter <= m_blocks_required; ++counter) {
63 const auto counter_encoded =
store_be(counter);
64 fn(std::span{counter_encoded}.last(m_counter_bytes),
65 std::span{outlen_encoded}.last(m_output_length_encoding_bytes));
70 CounterParams(uint32_t output_length_bits,
71 size_t output_length_encoding_bytes,
73 uint32_t blocks_required) :
74 m_output_length_bits(output_length_bits),
75 m_output_length_encoding_bytes(output_length_encoding_bytes),
76 m_counter_bytes(counter_bytes),
77 m_blocks_required(blocks_required) {}
80 uint32_t m_output_length_bits;
81 size_t m_output_length_encoding_bytes;
82 size_t m_counter_bytes;
83 uint32_t m_blocks_required;
89 m_prf(std::move(mac)), m_counter_bits(r), m_output_length_bits(L) {
90 CounterParams::validate_bit_lengths(m_counter_bits, m_output_length_bits);
95 return (m_counter_bits == 32 && m_output_length_bits == 32)
96 ?
fmt(
"SP800-108-Counter({})", m_prf->name())
97 :
fmt(
"SP800-108-Counter({},{},{})", m_prf->name(), m_counter_bits, m_output_length_bits);
101 return std::make_unique<SP800_108_Counter>(m_prf->new_object(), m_counter_bits, m_output_length_bits);
104void SP800_108_Counter::perform_kdf(std::span<uint8_t> key,
105 std::span<const uint8_t> secret,
106 std::span<const uint8_t> salt,
107 std::span<const uint8_t> label)
const {
112 const auto prf_len = m_prf->output_length();
113 const auto params = CounterParams::create_or_throw(key.size(), m_output_length_bits, m_counter_bits, prf_len);
115 constexpr uint8_t delim = 0;
117 BufferStuffer k(key);
118 m_prf->set_key(secret);
120 params.generate_blocks([&](
auto counter_encoded,
auto outlen_encoded) {
121 m_prf->update(counter_encoded);
122 m_prf->update(label);
123 m_prf->update(delim);
125 m_prf->update(outlen_encoded);
129 if(k.remaining_capacity() >= prf_len) {
130 m_prf->final(k.next(prf_len));
132 const auto h = m_prf->final();
133 k.append(std::span{h}.first(k.remaining_capacity()));
141 m_prf(std::move(mac)), m_counter_bits(r), m_output_length_bits(L) {
142 CounterParams::validate_bit_lengths(m_counter_bits, m_output_length_bits);
147 return (m_counter_bits == 32 && m_output_length_bits == 32)
148 ?
fmt(
"SP800-108-Feedback({})", m_prf->name())
149 :
fmt(
"SP800-108-Feedback({},{},{})", m_prf->name(), m_counter_bits, m_output_length_bits);
153 return std::make_unique<SP800_108_Feedback>(m_prf->new_object(), m_counter_bits, m_output_length_bits);
156void SP800_108_Feedback::perform_kdf(std::span<uint8_t> key,
157 std::span<const uint8_t> secret,
158 std::span<const uint8_t> salt,
159 std::span<const uint8_t> label)
const {
164 const auto prf_len = m_prf->output_length();
165 const auto iv_len = (salt.size() >= prf_len ? prf_len : 0);
166 constexpr uint8_t delim = 0;
167 const auto params = CounterParams::create_or_throw(key.size(), m_output_length_bits, m_counter_bits, prf_len);
169 BufferSlicer s(salt);
170 auto prev = s.copy_as_secure_vector(iv_len);
171 const auto ctx = s.take(s.remaining());
174 BufferStuffer k(key);
175 m_prf->set_key(secret);
177 params.generate_blocks([&](
auto counter_encoded,
auto outlen_encoded) {
179 m_prf->update(counter_encoded);
180 m_prf->update(label);
181 m_prf->update(delim);
183 m_prf->update(outlen_encoded);
186 const auto bytes_to_write = std::min(prev.size(), k.remaining_capacity());
187 k.append(std::span{prev}.first(bytes_to_write));
194 m_prf(std::move(mac)), m_counter_bits(r), m_output_length_bits(L) {
195 CounterParams::validate_bit_lengths(m_counter_bits, m_output_length_bits);
200 return (m_counter_bits == 32 && m_output_length_bits == 32)
201 ?
fmt(
"SP800-108-Pipeline({})", m_prf->name())
202 :
fmt(
"SP800-108-Pipeline({},{},{})", m_prf->name(), m_counter_bits, m_output_length_bits);
206 return std::make_unique<SP800_108_Pipeline>(m_prf->new_object(), m_counter_bits, m_output_length_bits);
209void SP800_108_Pipeline::perform_kdf(std::span<uint8_t> key,
210 std::span<const uint8_t> secret,
211 std::span<const uint8_t> salt,
212 std::span<const uint8_t> label)
const {
217 const auto prf_len = m_prf->output_length();
218 constexpr uint8_t delim = 0;
219 const auto params = CounterParams::create_or_throw(key.size(), m_output_length_bits, m_counter_bits, prf_len);
221 BufferStuffer k(key);
222 m_prf->set_key(secret);
225 params.generate_blocks([&](
auto counter_encoded,
auto outlen_encoded) {
226 auto incorporate_constant_input = [label, salt, outlen_encoded](MessageAuthenticationCode* prf) {
230 prf->update(outlen_encoded);
233 if(scratch.empty()) {
235 incorporate_constant_input(m_prf.get());
236 scratch = m_prf->final();
239 m_prf->update(scratch);
240 m_prf->final(scratch);
243 m_prf->update(scratch);
244 m_prf->update(counter_encoded);
245 incorporate_constant_input(m_prf.get());
249 if(k.remaining_capacity() >= prf_len) {
250 m_prf->final(k.next(prf_len));
254 m_prf->final(scratch);
255 k.append(std::span{scratch}.first(k.remaining_capacity()));
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
SP800_108_Counter(std::unique_ptr< MessageAuthenticationCode > mac, size_t r, size_t L)
std::string name() const override
std::unique_ptr< KDF > new_object() const override
std::string name() const override
SP800_108_Feedback(std::unique_ptr< MessageAuthenticationCode > mac, size_t r, size_t L)
std::unique_ptr< KDF > new_object() const override
std::unique_ptr< KDF > new_object() const override
std::string name() const override
SP800_108_Pipeline(std::unique_ptr< MessageAuthenticationCode > mac, size_t r, size_t L)
std::string fmt(std::string_view format, const T &... args)
BOTAN_FORCE_INLINE constexpr T ceil_division(T a, T b)
std::vector< T, secure_allocator< T > > secure_vector
constexpr auto store_be(ParamTs &&... params)