X-Git-Url: https://www.bearssl.org/gitweb//home/git/?p=BearSSL;a=blobdiff_plain;f=inc%2Fbearssl_rand.h;h=0a9f544fc4c58a82805d9b759eb6b21d8a001511;hp=0c3bc4deea7a19899d3c3f109bdd285edab2863a;hb=fb4296c593895fe6758f42642bcc4f6fea2f8710;hpb=3210f38e0491b39aec1ef419cb4114e9483089fb diff --git a/inc/bearssl_rand.h b/inc/bearssl_rand.h index 0c3bc4d..0a9f544 100644 --- a/inc/bearssl_rand.h +++ b/inc/bearssl_rand.h @@ -28,117 +28,253 @@ #include #include -/* - * Pseudo-Random Generators - * ------------------------ +#include "bearssl_block.h" +#include "bearssl_hash.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** \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). + * + * + * ## Procedural and OOP API + * + * 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 + * 219 bits (i.e. 64 kB of data); moreover, the context shall + * be reseeded at least once every 248 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 248 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. * - * 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 + * ## AESCTR_DRBG * - * 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. + * AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is + * meant to be used only in situations where you are desperate for + * speed, and have an hardware-optimized AES/CTR implementation. Whether + * this will yield perceptible improvements depends on what you use the + * pseudorandom bytes for, and how many you want; for instance, RSA key + * pair generation uses a substantial amount of randomness, and using + * AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key + * generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz). + * + * Internally, it uses CTR mode with successive counter values, starting + * at zero (counter value expressed over 128 bits, big-endian convention). + * The counter is not allowed to reach 32768; thus, every 32768*16 bytes + * at most, the `update()` function is run (on an empty seed, if none is + * provided). The `update()` function computes the new AES-128 key by + * applying a custom hash function to the concatenation of a state-dependent + * word (encryption of an all-one block with the current key) and the new + * seed. The custom hash function uses Hirose's construction over AES-256; + * see the comments in `aesctr_drbg.c` for details. + * + * This DRBG does not follow an existing standard, and thus should be + * considered as inadequate for production use until it has been properly + * analysed. */ +/** + * \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. - * - * 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. +/** + * \brief Context for HMAC_DRBG. + * + * 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. + * + * 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. * - * 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 `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) @@ -146,4 +282,116 @@ br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx) return ctx->digest_class; } +/** + * \brief Type for a provider of entropy seeds. + * + * A "seeder" is a function that is able to obtain random values from + * some source and inject them as entropy seed in a PRNG. A seeder + * shall guarantee that the total entropy of the injected seed is large + * enough to seed a PRNG for purposes of cryptographic key generation + * (i.e. at least 128 bits). + * + * A seeder may report a failure to obtain adequate entropy. Seeders + * shall endeavour to fix themselves transient errors by trying again; + * thus, callers may consider reported errors as permanent. + * + * \param ctx PRNG context to seed. + * \return 1 on success, 0 on error. + */ +typedef int (*br_prng_seeder)(const br_prng_class **ctx); + +/** + * \brief Get a seeder backed by the operating system or hardware. + * + * Get a seeder that feeds on RNG facilities provided by the current + * operating system or hardware. If no such facility is known, then 0 + * is returned. + * + * If `name` is not `NULL`, then `*name` is set to a symbolic string + * that identifies the seeder implementation. If no seeder is returned + * and `name` is not `NULL`, then `*name` is set to a pointer to the + * constant string `"none"`. + * + * \param name receiver for seeder name, or `NULL`. + * \return the system seeder, if available, or 0. + */ +br_prng_seeder br_prng_seeder_system(const char **name); + +/** + * \brief Context for AESCTR_DRBG. + * + * 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 + br_aes_gen_ctr_keys sk; + uint32_t cc; +#endif +} br_aesctr_drbg_context; + +/** + * \brief Statically allocated, constant vtable for AESCTR_DRBG. + */ +extern const br_prng_class br_aesctr_drbg_vtable; + +/** + * \brief AESCTR_DRBG initialisation. + * + * 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 internal AES key is first set to the all-zero key; then, the + * `br_aesctr_drbg_update()` function is called with the provided `seed`. + * The call is performed even if the seed length (`seed_len`) is zero. + * + * The `aesctr` parameter defines the underlying AES/CTR implementation. + * + * \param ctx AESCTR_DRBG context to initialise. + * \param aesctr vtable for the AES/CTR implementation. + * \param seed initial seed (can be `NULL` if `seed_len` is zero). + * \param seed_len initial seed length (in bytes). + */ +void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx, + const br_block_ctr_class *aesctr, const void *seed, size_t seed_len); + +/** + * \brief Random bytes generation with AESCTR_DRBG. + * + * This method produces `len` pseudorandom bytes, in the `out` + * buffer. The context is updated accordingly. + * + * \param ctx AESCTR_DRBG context. + * \param out output buffer. + * \param len number of pseudorandom bytes to produce. + */ +void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, + void *out, size_t len); + +/** + * \brief Inject additional seed bytes in AESCTR_DRBG. + * + * The provided seed bytes are added into the AESCTR_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 AESCTR_DRBG context. + * \param seed additional seed. + * \param seed_len additional seed length (in bytes). + */ +void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, + const void *seed, size_t seed_len); + +#ifdef __cplusplus +} +#endif + #endif