Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::span (and more) for Botan::RandomNumberGenerator #3195

Merged
merged 7 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions doc/migration_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -392,3 +392,17 @@ the constructor of the ``XMSS_PrivateKey``.
Private XMSS keys created this way use the old derivation logic and can therefore
generate new valid signatures. It is recommended to use
``WOTS_Derivation_Method::NIST_SP800_208`` (default) when creating new XMSS keys.

Random Number Generator
-----------------------

Fetching a large number of bytes via `randomize_with_input()` from a stateful
RNG will now incorporate the provided "input" data in the first request to the
underlying DRBG only. This applies to such DRBGs that pose a limit on the number
of bytes per request (most notable ``HMAC_DRBG`` with a 64kB default). Botan 2.x
(erroneously) applied the input to *all* underlying DRBG requests in such cases.

Applications that rely on a static seed for deterministic RNG output might
observe a different byte stream in such cases. As a workaround, users are
advised to "mimick" the legacy behaviour by manually pulling from the RNG in
"byte limit"-sized chunks and provide the "input" with each invocation.
36 changes: 18 additions & 18 deletions src/lib/ffi/ffi_rng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,34 +104,34 @@ int botan_rng_init_custom(botan_rng_t* rng_out, const char* rng_name, void* cont
Custom_RNG& operator=(const Custom_RNG& other) = delete;
Custom_RNG& operator=(Custom_RNG&& other) = delete;

void randomize(uint8_t output[], size_t length) override
protected:
void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) override
{
int rc = m_get_cb(m_context, output, length);
if(rc)
if(accepts_input() && !input.empty())
{
throw Botan::Invalid_State("Failed to get random from C callback, rc=" + std::to_string(rc));
int rc = m_add_entropy_cb(m_context, input.data(), input.size());
if(rc)
{
throw Botan::Invalid_State("Failed to add entropy via C callback, rc=" + std::to_string(rc));
}
}

if(!output.empty())
{
int rc = m_get_cb(m_context, output.data(), output.size());
if(rc)
{
throw Botan::Invalid_State("Failed to get random from C callback, rc=" + std::to_string(rc));
}
}
}

public:
bool accepts_input() const override
{
return m_add_entropy_cb != nullptr;
}

void add_entropy(const uint8_t input[], size_t length) override
{
if(m_add_entropy_cb == nullptr)
{
return;
}

int rc = m_add_entropy_cb(m_context, input, length);
if(rc)
{
throw Botan::Invalid_State("Failed to add entropy via C callback, rc=" + std::to_string(rc));
}
}

std::string name() const override
{
return m_name;
Expand Down
15 changes: 9 additions & 6 deletions src/lib/prov/pkcs11/p11_randomgenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ PKCS11_RNG::PKCS11_RNG(Session& session)
: m_session(session)
{}

void PKCS11_RNG::randomize(uint8_t output[], std::size_t length)
void PKCS11_RNG::fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input)
{
module()->C_GenerateRandom(m_session.get().handle(), output, Ulong(length));
}
if(!input.empty())
{
module()->C_SeedRandom(m_session.get().handle(), const_cast<uint8_t*>(input.data()), Ulong(input.size()));
}

void PKCS11_RNG::add_entropy(const uint8_t in[], std::size_t length)
{
module()->C_SeedRandom(m_session.get().handle(), const_cast<uint8_t*>(in), Ulong(length));
if(!output.empty())
{
module()->C_GenerateRandom(m_session.get().handle(), output.data(), Ulong(output.size()));
}
}

}
Expand Down
11 changes: 5 additions & 6 deletions src/lib/prov/pkcs11/p11_randomgenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,14 @@ class BOTAN_PUBLIC_API(2,0) PKCS11_RNG final : public Hardware_RNG
return m_session.get().module();
}

/// Calls `C_GenerateRandom` to generate random data
void randomize(uint8_t output[], std::size_t length) override;

/// Calls `C_SeedRandom` to add entropy to the random generation function of the token/middleware
void add_entropy(const uint8_t in[], std::size_t length) override;

// C_SeedRandom may suceed
bool accepts_input() const override { return true; }

private:
/// Calls `C_GenerateRandom` to generate random data
/// Calls `C_SeedRandom` to add entropy to the random generation function of the token/middleware
void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) override;

private:
const std::reference_wrapper<Session> m_session;
};
Expand Down
20 changes: 10 additions & 10 deletions src/lib/prov/tpm/tpm.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,20 @@ class BOTAN_PUBLIC_API(2,0) TPM_RNG final : public Hardware_RNG

bool accepts_input() const override { return true; }

void add_entropy(const uint8_t in[], size_t in_len) override
{
m_ctx.stir_random(in, in_len);
}

void randomize(uint8_t out[], size_t out_len) override
{
m_ctx.gen_random(out, out_len);
}

std::string name() const override { return "TPM_RNG"; }

bool is_seeded() const override { return true; }

private:
void fill_bytes_with_input(std::span<uint8_t> output, std::span<const uint8_t> input) override
{
if(!input.empty())
{ m_ctx.stir_random(input.data(), input.size()); }

if(!output.empty())
{ m_ctx.gen_random(output.data(), output.size()); }
}

private:
TPM_Context& m_ctx;
};
Expand Down
22 changes: 9 additions & 13 deletions src/lib/rng/auto_rng/auto_rng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include <botan/auto_rng.h>
#include <botan/entropy_src.h>
#include <botan/hmac_drbg.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/os_utils.h>

#include <array>

#if defined(BOTAN_HAS_SYSTEM_RNG)
#include <botan/system_rng.h>
Expand Down Expand Up @@ -83,27 +87,19 @@ std::string AutoSeeded_RNG::name() const
return m_rng->name();
}

void AutoSeeded_RNG::add_entropy(const uint8_t in[], size_t len)
{
m_rng->add_entropy(in, len);
}

size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs,
size_t poll_bits,
std::chrono::milliseconds poll_timeout)
{
return m_rng->reseed(srcs, poll_bits, poll_timeout);
}

void AutoSeeded_RNG::randomize(uint8_t output[], size_t output_len)
{
m_rng->randomize_with_ts_input(output, output_len);
}

void AutoSeeded_RNG::randomize_with_input(uint8_t output[], size_t output_len,
const uint8_t ad[], size_t ad_len)
void AutoSeeded_RNG::fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in)
{
m_rng->randomize_with_input(output, output_len, ad, ad_len);
if(in.empty())
{ m_rng->randomize_with_ts_input(out); }
else
{ m_rng->randomize_with_input(out, in); }
}

}
10 changes: 3 additions & 7 deletions src/lib/rng/auto_rng/auto_rng.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@ class Stateful_RNG;
class BOTAN_PUBLIC_API(2,0) AutoSeeded_RNG final : public RandomNumberGenerator
{
public:
void randomize(uint8_t out[], size_t len) override;

void randomize_with_input(uint8_t output[], size_t output_len,
const uint8_t input[], size_t input_len) override;

bool is_seeded() const override;

bool accepts_input() const override { return true; }
Expand All @@ -38,8 +33,6 @@ class BOTAN_PUBLIC_API(2,0) AutoSeeded_RNG final : public RandomNumberGenerator
size_t poll_bits = BOTAN_RNG_RESEED_POLL_BITS,
std::chrono::milliseconds poll_timeout = BOTAN_RNG_RESEED_DEFAULT_TIMEOUT) override;

void add_entropy(const uint8_t in[], size_t len) override;

std::string name() const override;

void clear() override;
Expand Down Expand Up @@ -93,6 +86,9 @@ class BOTAN_PUBLIC_API(2,0) AutoSeeded_RNG final : public RandomNumberGenerator

~AutoSeeded_RNG();

private:
void fill_bytes_with_input(std::span<uint8_t> out, std::span<const uint8_t> in) override;

private:
std::unique_ptr<Stateful_RNG> m_rng;
};
Expand Down
23 changes: 11 additions & 12 deletions src/lib/rng/chacha_rng/chacha_rng.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ ChaCha_RNG::ChaCha_RNG() : Stateful_RNG()
clear();
}

ChaCha_RNG::ChaCha_RNG(const secure_vector<uint8_t>& seed) : Stateful_RNG()
ChaCha_RNG::ChaCha_RNG(std::span<const uint8_t> seed) : Stateful_RNG()
{
m_hmac = MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
m_chacha = StreamCipher::create_or_throw("ChaCha(20)");
clear();
add_entropy(seed.data(), seed.size());
add_entropy(seed);
}

ChaCha_RNG::ChaCha_RNG(RandomNumberGenerator& underlying_rng,
Expand Down Expand Up @@ -58,24 +58,23 @@ void ChaCha_RNG::clear_state()
m_chacha->set_key(m_hmac->final());
}

void ChaCha_RNG::generate_output(uint8_t output[], size_t output_len,
const uint8_t input[], size_t input_len)
void ChaCha_RNG::generate_output(std::span<uint8_t> output, std::span<const uint8_t> input)
{
if(input_len > 0)
BOTAN_ASSERT_NOMSG(!output.empty());

if(!input.empty())
{
update(input, input_len);
update(input);
}

m_chacha->write_keystream(output, output_len);
m_chacha->write_keystream(output);
}

void ChaCha_RNG::update(const uint8_t input[], size_t input_len)
void ChaCha_RNG::update(std::span<const uint8_t> input)
{
m_hmac->update(input, input_len);
m_hmac->update(input);
m_chacha->set_key(m_hmac->final());

secure_vector<uint8_t> mac_key(m_hmac->output_length());
m_chacha->write_keystream(mac_key.data(), mac_key.size());
const auto mac_key = m_chacha->keystream_bytes(m_hmac->output_length());
m_hmac->set_key(mac_key);
}

Expand Down
7 changes: 3 additions & 4 deletions src/lib/rng/chacha_rng/chacha_rng.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class BOTAN_PUBLIC_API(2,3) ChaCha_RNG final : public Stateful_RNG
*
* @param seed the seed material, should be at least 256 bits
*/
ChaCha_RNG(const secure_vector<uint8_t>& seed);
ChaCha_RNG(std::span<const uint8_t> seed);

/**
* Automatic reseeding from @p underlying_rng will take place after
Expand Down Expand Up @@ -109,10 +109,9 @@ class BOTAN_PUBLIC_API(2,3) ChaCha_RNG final : public Stateful_RNG
size_t max_number_of_bytes_per_request() const override { return 0; }

private:
void update(const uint8_t input[], size_t input_len) override;
void update(std::span<const uint8_t> input) override;

void generate_output(uint8_t output[], size_t output_len,
const uint8_t input[], size_t input_len) override;
void generate_output(std::span<uint8_t> output, std::span<const uint8_t> input) override;

void clear_state() override;

Expand Down
44 changes: 22 additions & 22 deletions src/lib/rng/hmac_drbg/hmac_drbg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,54 +139,54 @@ std::string HMAC_DRBG::name() const
* HMAC_DRBG generation
* See NIST SP800-90A section 10.1.2.5
*/
void HMAC_DRBG::generate_output(uint8_t output[], size_t output_len,
const uint8_t input[], size_t input_len)
void HMAC_DRBG::generate_output(std::span<uint8_t> output, std::span<const uint8_t> input)
{
if(input_len > 0)
BOTAN_ASSERT_NOMSG(!output.empty());

if(!input.empty())
{
update(input, input_len);
update(input);
}

while(output_len > 0)
while(!output.empty())
{
const size_t to_copy = std::min(output_len, m_V.size());
m_mac->update(m_V.data(), m_V.size());
m_mac->final(m_V.data());
copy_mem(output, m_V.data(), to_copy);
const size_t to_copy = std::min(output.size(), m_V.size());
m_mac->update(m_V);
m_mac->final(m_V);
copy_mem(output.data(), m_V.data(), to_copy);

output += to_copy;
output_len -= to_copy;
output = output.subspan(to_copy);
}

update(input, input_len);
update(input);
}

/*
* Reset V and the mac key with new values
* See NIST SP800-90A section 10.1.2.2
*/
void HMAC_DRBG::update(const uint8_t input[], size_t input_len)
void HMAC_DRBG::update(std::span<const uint8_t> input)
{
secure_vector<uint8_t> T(m_V.size());
m_mac->update(m_V);
m_mac->update(0x00);
m_mac->update(input, input_len);
m_mac->final(T.data());
m_mac->update(input);
m_mac->final(T);
m_mac->set_key(T);

m_mac->update(m_V.data(), m_V.size());
m_mac->final(m_V.data());
m_mac->update(m_V);
m_mac->final(m_V);

if(input_len > 0)
if(!input.empty())
{
m_mac->update(m_V);
m_mac->update(0x01);
m_mac->update(input, input_len);
m_mac->final(T.data());
m_mac->update(input);
m_mac->final(T);
m_mac->set_key(T);

m_mac->update(m_V.data(), m_V.size());
m_mac->final(m_V.data());
m_mac->update(m_V);
m_mac->final(m_V);
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/lib/rng/hmac_drbg/hmac_drbg.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,10 +132,9 @@ class BOTAN_PUBLIC_API(2,0) HMAC_DRBG final : public Stateful_RNG
{ return m_max_number_of_bytes_per_request; }

private:
void update(const uint8_t input[], size_t input_len) override;
void update(std::span<const uint8_t> input) override;

void generate_output(uint8_t output[], size_t output_len,
const uint8_t input[], size_t input_len) override;
void generate_output(std::span<uint8_t> output, std::span<const uint8_t> input) override;

void clear_state() override;

Expand Down
Loading