More Doxygen-compatible documentation. Also unified two identical structures.

This commit is contained in:
Thomas Pornin 2016-11-19 19:05:08 +01:00
parent 60126cafc8
commit e683ebfe19
8 changed files with 568 additions and 320 deletions

View file

@ -28,117 +28,220 @@
#include <stddef.h>
#include <stdint.h>
/*
* Pseudo-Random Generators
* ------------------------
/** \file bearssl_rand.h
*
* # Pseudo-Random Generators
*
* A PRNG is a state-based engine that outputs pseudo-random bytes on
* demand. It is initialized with an initial seed, and additional seed
* bytes can be added afterwards. Bytes produced depend on the seeds
* and also on the exact sequence of calls (including sizes requested
* for each call).
* bytes can be added afterwards. Bytes produced depend on the seeds and
* also on the exact sequence of calls (including sizes requested for
* each call).
*
* An object-oriented API is defined, with rules similar to that of
* hash functions. The context structure for a PRNG must start with
* a pointer to the vtable. The vtable contains the following fields:
*
* context_size size of the context structure for this PRNG
* init initialize context with an initial seed
* generate produce some pseudo-random bytes
* update insert some additional seed
* ## Procedural and OOP API
*
* Note that the init() method may accept additional parameters, provided
* as a 'const void *' pointer at API level. These additional parameters
* depend on the implemented PRNG.
* For the PRNG of name "`xxx`", two API are provided. The _procedural_
* API defined a context structure `br_xxx_context` and three functions:
*
* - `br_xxx_init()`
*
* Initialise the context with an initial seed.
*
* - `br_xxx_generate()`
*
* Produce some pseudo-random bytes.
*
* - `br_xxx_update()`
*
* Inject some additional seed.
*
* The initialisation function sets the first context field (`vtable`)
* to a pointer to the vtable that supports the OOP API. The OOP API
* provides access to the same functions through function pointers,
* named `init()`, `generate()` and `update()`.
*
* Note that the context initialisation method may accept additional
* parameters, provided as a 'const void *' pointer at API level. These
* additional parameters depend on the implemented PRNG.
*
*
* ## HMAC_DRBG
*
* HMAC_DRBG is defined in [NIST SP 800-90A Revision
* 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf).
* It uses HMAC repeatedly, over some configurable underlying hash
* function. In BearSSL, it is implemented under the "`hmac_drbg`" name.
* The "extra parameters" pointer for context initialisation should be
* set to a pointer to the vtable for the underlying hash function (e.g.
* pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256).
*
* According to the NIST standard, each request shall produce up to
* 2<sup>19</sup> bits (i.e. 64 kB of data); moreover, the context shall
* be reseeded at least once every 2<sup>48</sup> requests. This
* implementation does not maintain the reseed counter (the threshold is
* too high to be reached in practice) and does not object to producing
* more than 64 kB in a single request; thus, the code cannot fail,
* which corresponds to the fact that the API has no room for error
* codes. However, this implies that requesting more than 64 kB in one
* `generate()` request, or making more than 2<sup>48</sup> requests
* without reseeding, is formally out of NIST specification. There is
* no currently known security penalty for exceeding the NIST limits,
* and, in any case, HMAC_DRBG usage in implementing SSL/TLS always
* stays much below these thresholds.
*/
/**
* \brief Class type for PRNG implementations.
*
* A `br_prng_class` instance references the methods implementing a PRNG.
* Constant instances of this structure are defined for each implemented
* PRNG. Such instances are also called "vtables".
*/
typedef struct br_prng_class_ br_prng_class;
struct br_prng_class_ {
/**
* \brief Size (in bytes) of the context structure appropriate for
* running this PRNG.
*/
size_t context_size;
/**
* \brief Initialisation method.
*
* The context to initialise is provided as a pointer to its
* first field (the vtable pointer); this function sets that
* first field to a pointer to the vtable.
*
* The extra parameters depend on the implementation; each
* implementation defines what kind of extra parameters it
* expects (if any).
*
* Requirements on the initial seed depend on the implemented
* PRNG.
*
* \param ctx PRNG context to initialise.
* \param params extra parameters for the PRNG.
* \param seed initial seed.
* \param seed_len initial seed length (in bytes).
*/
void (*init)(const br_prng_class **ctx, const void *params,
const void *seed, size_t seed_len);
/**
* \brief Random bytes generation.
*
* This method produces `len` pseudorandom bytes, in the `out`
* buffer. The context is updated accordingly.
*
* \param ctx PRNG context.
* \param out output buffer.
* \param len number of pseudorandom bytes to produce.
*/
void (*generate)(const br_prng_class **ctx, void *out, size_t len);
/**
* \brief Inject additional seed bytes.
*
* The provided seed bytes are added into the PRNG internal
* entropy pool.
*
* \param ctx PRNG context.
* \param seed additional seed.
* \param seed_len additional seed length (in bytes).
*/
void (*update)(const br_prng_class **ctx,
const void *seed, size_t seed_len);
};
/*
* HMAC_DRBG is a pseudo-random number generator based on HMAC (with
* an underlying hash function). HMAC_DRBG is specified in NIST Special
* Publication 800-90A. It works as a stateful machine:
* -- It has an internal state.
* -- The state can be updated with additional "entropy" (some bytes
* provided from the outside).
* -- Each request is for some bits (up to some limit). For each request,
* an internal "reseed counter" is incremented.
* -- When the reseed counter reaches a given threshold, a reseed is
* necessary.
/**
* \brief Context for HMAC_DRBG.
*
* Standard limits are quite high: each request can produce up to 2^19
* bits (i.e. 64 kB of data), and the threshold for the reseed counter
* is 2^48. In practice, we cannot really reach that reseed counter, so
* the implementation simply omits the counter. Similarly, we consider
* that it is up to callers NOT to ask for more than 64 kB of randomness
* in one go. Under these conditions, this implementation cannot fail,
* and thus functions need not return any status code.
*
* (Asking for more than 64 kB of data in one generate() call won't make
* the implementation fail, and, as far as we know, it will not induce
* any actual weakness; this is "merely" out of the formal usage range
* defined for HMAC_DRBG.)
*
* A dedicated context structure (caller allocated, as usual) contains
* the current PRNG state.
*
* For the OOP interface, the "additional parameters" are a pointer to
* the class of the hash function to use.
* The context contents are opaque, except the first field, which
* supports OOP.
*/
typedef struct {
/**
* \brief Pointer to the vtable.
*
* This field is set with the initialisation method/function.
*/
const br_prng_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
unsigned char K[64];
unsigned char V[64];
const br_hash_class *digest_class;
#endif
} br_hmac_drbg_context;
/**
* \brief Statically allocated, constant vtable for HMAC_DRBG.
*/
extern const br_prng_class br_hmac_drbg_vtable;
/*
* Initialize a HMAC_DRBG instance, with the provided initial seed (of
* 'len' bytes). The 'seed' used here is what is called, in SP 800-90A
* terminology, the concatenation of the "seed", "nonce" and
* "personalization string", in that order.
/**
* \brief HMAC_DRBG initialisation.
*
* Formally, the underlying digest can only be SHA-1 or one of the SHA-2
* functions. This implementation also works with any other implemented
* hash function (e.g. MD5), but such usage is non-standard and not
* recommended.
* The context to initialise is provided as a pointer to its first field
* (the vtable pointer); this function sets that first field to a
* pointer to the vtable.
*
* The `seed` value is what is called, in NIST terminology, the
* concatenation of the "seed", "nonce" and "personalization string", in
* that order.
*
* The `digest_class` parameter defines the underlying hash function.
* Formally, the NIST standard specifies that the hash function shall
* be only SHA-1 or one of the SHA-2 functions. This implementation also
* works with any other implemented hash function (such as MD5), but
* this is non-standard and therefore not recommended.
*
* \param ctx HMAC_DRBG context to initialise.
* \param digest_class vtable for the underlying hash function.
* \param seed initial seed.
* \param seed_len initial seed length (in bytes).
*/
void br_hmac_drbg_init(br_hmac_drbg_context *ctx,
const br_hash_class *digest_class, const void *seed, size_t len);
const br_hash_class *digest_class, const void *seed, size_t seed_len);
/*
* Obtain some pseudorandom bits from HMAC_DRBG. The provided context
* is updated. The output bits are written in 'out' ('len' bytes). The
* size of the requested chunk of pseudorandom bits MUST NOT exceed
* 64 kB (the function won't fail if more bytes are requested, but
* the usage will be outside of the HMAC_DRBG specification limits).
/**
* \brief Random bytes generation with HMAC_DRBG.
*
* This method produces `len` pseudorandom bytes, in the `out`
* buffer. The context is updated accordingly. Formally, requesting
* more than 65536 bytes in one request falls out of specification
* limits (but it won't fail).
*
* \param ctx HMAC_DRBG context.
* \param out output buffer.
* \param len number of pseudorandom bytes to produce.
*/
void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len);
/*
* Update an HMAC_DRBG instance with some new entropy. The extra 'seed'
* complements the current state but does not completely replace any
* previous seed. The process is such that pushing new entropy, even of
* questionable quality, will not make the output "less random" in any
* practical way.
/**
* \brief Inject additional seed bytes in HMAC_DRBG.
*
* The provided seed bytes are added into the HMAC_DRBG internal
* entropy pool. The process does not _replace_ existing entropy,
* thus pushing non-random bytes (i.e. bytes which are known to the
* attackers) does not degrade the overall quality of generated bytes.
*
* \param ctx HMAC_DRBG context.
* \param seed additional seed.
* \param seed_len additional seed length (in bytes).
*/
void br_hmac_drbg_update(br_hmac_drbg_context *ctx,
const void *seed, size_t len);
const void *seed, size_t seed_len);
/*
* Get the hash function implementation used by a given instance of
/**
* \brief Get the hash function implementation used by a given instance of
* HMAC_DRBG.
*
* This calls MUST NOT be performed on a context which was not
* previously initialised.
*
* \param ctx HMAC_DRBG context.
* \return the hash function vtable.
*/
static inline const br_hash_class *
br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx)