Skip to content

Commit

Permalink
Merge pull request #3195 from randombit/feature/random_something
Browse files Browse the repository at this point in the history
std::span (and more) for Botan::RandomNumberGenerator
  • Loading branch information
reneme authored Mar 22, 2023
2 parents 02ae99a + 4e6c3e2 commit 88eaa00
Show file tree
Hide file tree
Showing 24 changed files with 473 additions and 411 deletions.
14 changes: 14 additions & 0 deletions doc/migration_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,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 @@ -107,27 +111,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

0 comments on commit 88eaa00

Please sign in to comment.