blob: e3d0f3f16081c39f269677a6a8f683c1bea8f5c1 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_LIB_CRYPTO_INCLUDE_LIB_CRYPTO_PRNG_H_
#define ZIRCON_KERNEL_LIB_CRYPTO_INCLUDE_LIB_CRYPTO_PRNG_H_
#include <lib/crypto/entropy_pool.h>
#include <lib/lazy_init/lazy_init.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <stddef.h>
#include <stdint.h>
#include <kernel/event.h>
#include <kernel/mutex.h>
#include <kernel/spinlock.h>
#include <ktl/atomic.h>
namespace crypto {
typedef unsigned __int128 uint128_t;
// This exposes a (optionally-)thread-safe cryptographically secure PRNG.
// This PRNG must be seeded with at least 256 bits of "real" entropy before
// being used for cryptographic applications.
class Prng {
public:
// Tag object for constructing a non-thread-safe version.
struct NonThreadSafeTag {};
// Construct a thread-safe instance of the PRNG with the input pool. The pool provides must
// provide at least 256 bits of entropy.
explicit Prng(EntropyPool pool)
: pool_(std::move(pool)),
nonce_(0),
is_thread_safe_(true),
accumulated_(pool_.contents().size()) {}
// Construct a thread-safe instance of the PRNG with the byte array at
// |data| as the initial seed. |size| is the length of |data| in bytes.
Prng(const void* data, size_t size);
// Construct a non-thread-safe instance of the PRNG with the byte array at
// |data| as the initial seed. |size| is the length of |data| in bytes.
Prng(const void* data, size_t size, NonThreadSafeTag);
~Prng();
// Re-seed the PRNG by mixing-in new entropy. |size| is in bytes.
// |size| MUST NOT be greater than kMaxEntropy.
// If size is 0, only hash of the current key is used to re-seed.
void AddEntropy(const void* data, size_t size) TA_EXCL(add_entropy_lock_) TA_EXCL(pool_lock_);
// Re-seed the PRNG by hash of the current key. This does not mix in new
// entropy.
void SelfReseed();
// Get pseudo-random output of |size| bytes. Blocks until at least
// kMinEntropy bytes of entropy have been added to this PRNG. |size| MUST
// NOT be greater than kMaxDrawLen. Identical PRNGs are only guaranteed to
// produce identical output when given identical inputs.
void Draw(void* out, size_t size) TA_EXCL(pool_lock_);
// Return an integer in the range [0, exclusive_upper_bound) chosen
// uniformly at random. This is a wrapper for Draw(), and so has the same
// caveats.
uint64_t RandInt(uint64_t exclusive_upper_bound) TA_EXCL(pool_lock_);
// Transitions the PRNG to thread-safe mode. This asserts that the
// instance is not yet thread-safe.
void BecomeThreadSafe();
// Inspect if this PRNG is thread-safe.
bool is_thread_safe() const;
// The minimum amount of entropy (in bytes) the generator requires before
// Draw will return data.
static constexpr uint64_t kMinEntropy = 32;
// The maximum amount of entropy (in bytes) that can be submitted to
// AddEntropy. Anything above this will panic.
static constexpr uint64_t kMaxEntropy = 1ULL << 30;
// The maximum amount of pseudorandom data (in bytes) that can be drawn in
// one call to Draw. This the limit imposed by the maximum number of bytes
// that can be generated with a single key/nonce pair. Each request to Draw
// uses a different key/nonce pair. Anything above this will panic.
static constexpr uint64_t kMaxDrawLen = 1ULL << 38;
private:
Prng(const Prng&) = delete;
Prng& operator=(const Prng&) = delete;
// Synchronizes calls to |AddEntropy|.
DECLARE_MUTEX(Prng) add_entropy_lock_;
// Controls access to |key_| |and nonce_|.
DECLARE_SPINLOCK(Prng) pool_lock_;
// ChaCha20 key(pool_) and nonce as described in RFC 7539.
EntropyPool pool_ TA_GUARDED(pool_lock_);
uint128_t nonce_ TA_GUARDED(pool_lock_);
// Event used to signal when calls to |Draw| may proceed. This is initialized when
// |BecomeThreadSafe| is called.
lazy_init::LazyInit<Event> ready_;
bool is_thread_safe_ = false;
// Number of bytes of entropy added so far.
ktl::atomic<size_t> accumulated_;
};
} // namespace crypto
#endif // ZIRCON_KERNEL_LIB_CRYPTO_INCLUDE_LIB_CRYPTO_PRNG_H_