/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1 * for SHA-1, SHA-224, and SHA-256 it's 440 bits.
* for SHA-384 and SHA-512 it's 888 bits */ #define PRNG_SEEDLEN (440 / PR_BITS_PER_BYTE) #define PRNG_MAX_ADDITIONAL_BYTES PR_INT64(0x100000000) /* 2^35 bits or 2^32 bytes */ #define PRNG_MAX_REQUEST_SIZE 0x10000 /* 2^19 bits or 2^16 bytes */ #define PRNG_ADDITONAL_DATA_CACHE_SIZE (8 * 1024) /* must be less than \ * PRNG_MAX_ADDITIONAL_BYTES \
*/ #define PRNG_ENTROPY_BLOCK_SIZE SHA256_LENGTH
/* RESEED_COUNT is how many calls to the prng before we need to reseed * under normal NIST rules, you must return an error. In the NSS case, we * self-reseed with RNG_SystemRNG(). Count can be a large number. For code * simplicity, we specify count with 2 components: RESEED_BYTE (which is * the same as LOG256(RESEED_COUNT)) and RESEED_VALUE (which is the same as * RESEED_COUNT / (256 ^ RESEED_BYTE)). Another way to look at this is * RESEED_COUNT = RESEED_VALUE * (256 ^ RESEED_BYTE). For Hash based DRBG * we use the maximum count value, 2^48, or RESEED_BYTE=6 and RESEED_VALUE=1
*/ #define RESEED_BYTE 6 #define RESEED_VALUE 1
/* * The actual values of this enum are specified in SP 800-90, 10.1.1.* * The spec does not name the types, it only uses bare values
*/ typedefenum {
prngCGenerateType = 0, /* used when creating a new 'C' */
prngReseedType = 1, /* used in reseeding */
prngAdditionalDataType = 2, /* used in mixing additional data */
prngGenerateByteType = 3 /* used when mixing internal state while
* generating bytes */
} prngVTypes;
/* * Global RNG context
*/ struct RNGContextStr {
PZLock *lock; /* Lock to serialize access to global rng */ /* * NOTE, a number of steps in the drbg algorithm need to hash * V_type || V. The code, therefore, depends on the V array following * immediately after V_type to avoid extra copies. To accomplish this * in a way that compiliers can't perturb, we declare V_type and V
* as a V_Data array and reference them by macros */
PRUint8 V_Data[PRNG_SEEDLEN + 1]; /* internal state variables */ #define V_type V_Data[0] #define V(rng) (((rng)->V_Data) + 1) #define VSize(rng) ((sizeof(rng)->V_Data) - 1)
PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */ /* If we get calls for the PRNG to return less than the length of our * hash, we extend the request for a full hash (since we'll be doing * the full hash anyway). Future requests for random numbers are fulfilled * from the remainder of the bytes we generated. Requests for bytes longer * than the hash size are fulfilled directly from the HashGen function
* of the random number generator. */
PRUint8 reseed_counter[RESEED_BYTE + 1]; /* number of requests since the * last reseed. Need only be * big enough to hold the whole
* reseed count */
PRUint8 data[SHA256_LENGTH]; /* when we request less than a block * save the rest of the rng output for
* another partial block */
PRUint8 dataAvail; /* # bytes of output available in our cache,
* [0...SHA256_LENGTH] */ /* store additional data that has been shovelled off to us by
* RNG_RandomUpdate. */
PRUint8 additionalDataCache[PRNG_ADDITONAL_DATA_CACHE_SIZE];
PRUint32 additionalAvail;
PRBool isValid; /* false if RNG reaches an invalid state */
PRBool isKatTest; /* true if running NIST PRNG KAT tests */ /* for continuous entropy check */
PRUint8 previousEntropyHash[SHA256_LENGTH];
};
/* * The next several functions are derived from the NIST SP 800-90 * spec. In these functions, an attempt was made to use names consistent * with the names in the spec, even if they differ from normal NSS usage.
*/
/* * Hash Derive function defined in NISP SP 800-90 Section 10.4.1. * This function is used in the Instantiate and Reseed functions. * * NOTE: requested_bytes cannot overlap with input_string_1 or input_string_2. * input_string_1 and input_string_2 are logically concatentated. * input_string_1 must be supplied. * if input_string_2 is not supplied, NULL should be passed for this parameter.
*/ static SECStatus
prng_Hash_df(PRUint8 *requested_bytes, unsignedint no_of_bytes_to_return, const PRUint8 *input_string_1, unsignedint input_string_1_len, const PRUint8 *input_string_2, unsignedint input_string_2_len)
{
SHA256Context ctx;
PRUint32 tmp;
PRUint8 counter;
/* * Hash_DRBG Instantiate NIST SP 800-90 10.1.1.2 * * NOTE: bytes & len are entropy || nonce || personalization_string. In * normal operation, NSS calculates them all together in a single call.
*/ static SECStatus
prng_instantiate(RNGContext *rng, const PRUint8 *bytes, unsignedint len)
{ if (!rng->isKatTest && len < PRNG_SEEDLEN) { /* If the seedlen is too small, it's probably because we failed to get * enough random data. * This is stricter than NIST SP800-90A requires. Don't enforce it for
* tests. */
PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure;
}
prng_Hash_df(V(rng), VSize(rng), bytes, len, NULL, 0);
rng->V_type = prngCGenerateType;
prng_Hash_df(rng->C, sizeof(rng->C), rng->V_Data, sizeof(rng->V_Data),
NULL, 0);
PRNG_RESET_RESEED_COUNT(rng) return SECSuccess;
}
/* For FIPS 140-2 4.9.2 continuous random number generator test, * fetch the initial entropy from the system RNG and keep it for
* later comparison. */
length = RNG_SystemRNG(block, sizeof(block)); if (length == 0) { return PR_FAILURE; /* error is already set */
}
PORT_Assert(length == sizeof(block));
/* Store the hash of the entropy block rather than the block
* itself for backward secrecy. */
SHA256_Begin(&ctx);
SHA256_Update(&ctx, block, sizeof(block));
SHA256_End(&ctx, globalrng->previousEntropyHash, NULL, sizeof(globalrng->previousEntropyHash));
PORT_SafeZero(block, sizeof(block));
SHA256_DestroyContext(&ctx, PR_FALSE); return PR_SUCCESS;
}
if (PR_CallOnce(&coRNGInitEntropy, prng_initEntropy) != PR_SUCCESS) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
}
/* For FIPS 140-2 4.9.2 continuous random generator test, * iteratively fetch fixed sized blocks from the system and
* compare consecutive blocks. */ while (total < requestLength) {
size_t length = RNG_SystemRNG(block, sizeof(block)); if (length == 0) {
rv = SECFailure; /* error is already set */ goto out;
}
PORT_Assert(length == sizeof(block));
/* Store the hash of the entropy block rather than the block
* itself for backward secrecy. */
SHA256_Begin(&ctx);
SHA256_Update(&ctx, block, sizeof(block));
SHA256_End(&ctx, hash, NULL, sizeof(hash));
/* * Update the global random number generator with more seeding * material. Use the Hash_DRBG reseed algorithm from NIST SP-800-90 * section 10.1.1.3 * * If entropy is NULL, it is fetched from the noise generator.
*/ static SECStatus
prng_reseed(RNGContext *rng, const PRUint8 *entropy, unsignedint entropy_len, const PRUint8 *additional_input, unsignedint additional_input_len)
{
PRUint8 noiseData[(sizeof(rng->V_Data)) + PRNG_SEEDLEN];
PRUint8 *noise = &noiseData[0];
SECStatus rv;
/* if entropy wasn't supplied, fetch it. (normal operation case) */ if (entropy == NULL) {
entropy_len = PRNG_SEEDLEN;
rv = prng_getEntropy(&noiseData[sizeof(rng->V_Data)], entropy_len); if (rv != SECSuccess) { return SECFailure; /* error is already set */
}
} else { /* NOTE: this code is only available for testing, not to applications */ /* if entropy was too big for the stack variable, get it from malloc */ if (entropy_len > PRNG_SEEDLEN) {
noise = PORT_Alloc(entropy_len + (sizeof(rng->V_Data))); if (noise == NULL) { return SECFailure;
}
}
PORT_Memcpy(&noise[sizeof(rng->V_Data)], entropy, entropy_len);
}
if (entropy_len < 256 / PR_BITS_PER_BYTE) { /* noise == &noiseData[0] at this point, so nothing to free */
PORT_SetError(SEC_ERROR_NEED_RANDOM); return SECFailure;
}
if (noise != &noiseData[0]) {
PORT_Free(noise);
} return SECSuccess;
}
/* * SP 800-90 requires we rerun our health tests on reseed
*/ static SECStatus
prng_reseed_test(RNGContext *rng, const PRUint8 *entropy, unsignedint entropy_len, const PRUint8 *additional_input, unsignedint additional_input_len)
{
SECStatus rv;
/* do health checks in FIPS mode */
rv = PRNGTEST_RunHealthTests(); if (rv != SECSuccess) { /* error set by PRNGTEST_RunHealTests() */
rng->isValid = PR_FALSE; return SECFailure;
} return prng_reseed(rng, entropy, entropy_len,
additional_input, additional_input_len);
}
/* * build some fast inline functions for adding.
*/ #define PRNG_ADD_CARRY_ONLY(dest, start, carry) \
{ \ int k1; \ for (k1 = start; carry && k1 >= 0; k1--) { \
carry = !(++dest[k1]); \
} \
}
/* * NOTE: dest must be an array for the following to work.
*/ #define PRNG_ADD_BITS(dest, dest_len, add, len, carry) \
carry = 0; \
PORT_Assert((dest_len) >= (len)); \
{ \ int k1, k2; \ for (k1 = dest_len - 1, k2 = len - 1; k2 >= 0; --k1, --k2) { \
carry += dest[k1] + add[k2]; \
dest[k1] = (PRUint8)carry; \
carry >>= 8; \
} \
}
/* * This function expands the internal state of the prng to fulfill any number * of bytes we need for this request. We only use this call if we need more * than can be supplied by a single call to SHA256_HashBuf. * * This function is specified in NIST SP 800-90 section 10.1.1.4, Hashgen
*/ staticvoid
prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes, unsignedint no_of_returned_bytes)
{
PRUint8 data[VSize(rng)];
PRUint8 thisHash[SHA256_LENGTH];
SHA256_Begin(&ctx);
SHA256_Update(&ctx, data, sizeof(data));
SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH); if (no_of_returned_bytes < SHA256_LENGTH) {
len = no_of_returned_bytes;
}
PORT_Memcpy(returned_bytes, thisHash, len);
returned_bytes += len;
no_of_returned_bytes -= len; /* The carry parameter is a bool (increment or not).
* This increments data if no_of_returned_bytes is not zero */
carry = no_of_returned_bytes;
PRNG_ADD_CARRY_ONLY(data, (sizeof(data)) - 1, carry);
SHA256_DestroyContext(&ctx, PR_FALSE);
}
PORT_SafeZero(data, sizeof(data));
PORT_SafeZero(thisHash, sizeof(thisHash));
}
/* * Generates new random bytes and advances the internal prng state. * additional bytes are only used in algorithm testing. * * This function is specified in NIST SP 800-90 section 10.1.1.4
*/ static SECStatus
prng_generateNewBytes(RNGContext *rng,
PRUint8 *returned_bytes, unsignedint no_of_returned_bytes, const PRUint8 *additional_input, unsignedint additional_input_len)
{
PRUint8 H[SHA256_LENGTH]; /* both H and w since they
* aren't used concurrently */ unsignedint carry;
if (!rng->isValid) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} /* This code only triggers during tests, normal
* prng operation does not use additional_input */ if (additional_input) {
SHA256Context ctx; /* NIST SP 800-90 defines two temporaries in their calculations, * w and H. These temporaries are the same lengths, and used * at different times, so we use the following macro to collapse * them to the same variable, but keeping their unique names for
* easy comparison to the spec */ #define w H
rng->V_type = prngAdditionalDataType;
SHA256_Begin(&ctx);
SHA256_Update(&ctx, rng->V_Data, sizeof(rng->V_Data));
SHA256_Update(&ctx, additional_input, additional_input_len);
SHA256_End(&ctx, w, NULL, sizeof(w));
PRNG_ADD_BITS_AND_CARRY(V(rng), VSize(rng), w, sizeof(w), carry)
PORT_Memset(w, 0, sizeof(w));
SHA256_DestroyContext(&ctx, PR_FALSE); #undef w
}
/* if the prng failed, don't return any output, signal softoken */
PORT_SafeZero(H, sizeof(H)); if (!rng->isValid) {
PORT_Memset(returned_bytes, 0, no_of_returned_bytes);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} return SECSuccess;
}
/* Use NSPR to prevent RNG_RNGInit from being called from separate * threads, creating a race condition.
*/ staticconst PRCallOnceType pristineCallOnce; static PRCallOnceType coRNGInit; static PRStatus
rng_init(void)
{
PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */
SECStatus rv = SECSuccess;
if (globalrng == NULL) { /* bytes needs to have enough space to hold
* a SHA256 hash value. Blow up at compile time if this isn't true */
PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH); /* create a new global RNG context */
globalrng = &theGlobalRng;
PORT_Assert(NULL == globalrng->lock); /* create a lock for it */
globalrng->lock = PZ_NewLock(nssILockOther); if (globalrng->lock == NULL) {
globalrng = NULL;
PORT_SetError(PR_OUT_OF_MEMORY_ERROR); return PR_FAILURE;
}
/* Try to get some seed data for the RNG */
rv = prng_getEntropy(bytes, sizeof(bytes)); if (rv == SECSuccess) { /* if this is our first call, instantiate, otherwise reseed * prng_instantiate gets a new clean state, we want to mix
* any previous entropy we may have collected */ if (V(globalrng)[0] == 0) {
rv = prng_instantiate(globalrng, bytes, sizeof(bytes));
} else {
rv = prng_reseed_test(globalrng, bytes, sizeof(bytes), NULL, 0);
}
memset(bytes, 0, sizeof(bytes));
} else {
PZ_DestroyLock(globalrng->lock);
globalrng->lock = NULL;
globalrng = NULL; return PR_FAILURE;
} if (rv != SECSuccess) { return PR_FAILURE;
}
/* the RNG is in a valid state */
globalrng->isValid = PR_TRUE;
globalrng->isKatTest = PR_FALSE;
/* fetch one random value so that we can populate rng->oldV for our
* continous random number test. */
prng_generateNewBytes(globalrng, bytes, SHA256_LENGTH, NULL, 0);
/* Fetch more entropy into the PRNG */
RNG_SystemInfoForRNG();
} return PR_SUCCESS;
}
/* * Clean up the global RNG context
*/ staticvoid
prng_freeRNGContext(RNGContext *rng)
{
PRUint8 inputhash[VSize(rng) + (sizeof(rng->C))];
/* zero global RNG context except for C & V to preserve entropy */
prng_Hash_df(inputhash, sizeof(rng->C), rng->C, sizeof(rng->C), NULL, 0);
prng_Hash_df(&inputhash[sizeof(rng->C)], VSize(rng), V(rng), VSize(rng),
NULL, 0);
memset(rng, 0, sizeof(*rng));
memcpy(rng->C, inputhash, sizeof(rng->C));
memcpy(V(rng), &inputhash[sizeof(rng->C)], VSize(rng));
memset(inputhash, 0, sizeof(inputhash));
}
/* * Public functions
*/
/* * Initialize the global RNG context and give it some seed input taken * from the system. This function is thread-safe and will only allow * the global context to be initialized once. The seed input is likely * small, so it is imperative that RNG_RandomUpdate() be called with * additional seed data before the generator is used. A good way to * provide the generator with additional entropy is to call * RNG_SystemInfoForRNG(). Note that C_Initialize() does exactly that.
*/
SECStatus
RNG_RNGInit(void)
{ /* Allow only one call to initialize the context */
PR_CallOnce(&coRNGInit, rng_init); /* Make sure there is a context */ return (globalrng != NULL) ? SECSuccess : SECFailure;
}
/* ** Update the global random number generator with more seeding ** material.
*/
SECStatus
RNG_RandomUpdate(constvoid *data, size_t bytes)
{
SECStatus rv;
/* Make sure our assumption that size_t is unsigned is true */
PR_STATIC_ASSERT(((size_t)-1) > (size_t)1);
#ifdefined(NS_PTR_GT_32) || (defined(NSS_USE_64) && !defined(NS_PTR_LE_32)) /* * NIST 800-90 requires us to verify our inputs. This value can * come from the application, so we need to make sure it's within the * spec. The spec says it must be less than 2^32 bytes (2^35 bits). * This can only happen if size_t is greater than 32 bits (i.e. on * most 64 bit platforms). The 90% case (perhaps 100% case), size_t * is less than or equal to 32 bits if the platform is not 64 bits, and * greater than 32 bits if it is a 64 bit platform. The corner * cases are handled with explicit defines NS_PTR_GT_32 and NS_PTR_LE_32. * * In general, neither NS_PTR_GT_32 nor NS_PTR_LE_32 will need to be * defined. If you trip over the next two size ASSERTS at compile time, * you will need to define them for your platform. * * if 'sizeof(size_t) > 4' is triggered it means that we were expecting * sizeof(size_t) to be greater than 4, but it wasn't. Setting * NS_PTR_LE_32 will correct that mistake. * * if 'sizeof(size_t) <= 4' is triggered, it means that we were expecting * sizeof(size_t) to be less than or equal to 4, but it wasn't. Setting * NS_PTR_GT_32 will correct that mistake.
*/
PZ_Lock(globalrng->lock); /* if we're passed more than our additionalDataCache, simply
* call reseed with that data */ if (bytes > sizeof(globalrng->additionalDataCache)) {
rv = prng_reseed_test(globalrng, NULL, 0, data, (unsignedint)bytes); /* if we aren't going to fill or overflow the buffer, just cache it */
} elseif (bytes < ((sizeof(globalrng->additionalDataCache)) - globalrng->additionalAvail)) {
PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
data, bytes);
globalrng->additionalAvail += (PRUint32)bytes;
rv = SECSuccess;
} else { /* we are going to fill or overflow the buffer. In this case we will * fill the entropy buffer, reseed with it, start a new buffer with the * remainder. We know the remainder will fit in the buffer because * we already handled the case where bytes > the size of the buffer.
*/
size_t bufRemain = (sizeof(globalrng->additionalDataCache)) - globalrng->additionalAvail; /* fill the rest of the buffer */ if (bufRemain) {
PORT_Memcpy(globalrng->additionalDataCache + globalrng->additionalAvail,
data, bufRemain);
data = ((unsignedchar *)data) + bufRemain;
bytes -= bufRemain;
} /* reseed from buffer */
rv = prng_reseed_test(globalrng, NULL, 0,
globalrng->additionalDataCache, sizeof(globalrng->additionalDataCache));
/* copy the rest into the cache */
PORT_Memcpy(globalrng->additionalDataCache, data, bytes);
globalrng->additionalAvail = (PRUint32)bytes;
}
PZ_Unlock(globalrng->lock); return rv;
}
/* ** Generate some random bytes, using the global random number generator ** object.
*/ static SECStatus
prng_GenerateGlobalRandomBytes(RNGContext *rng, void *dest, size_t len)
{
SECStatus rv = SECSuccess;
PRUint8 *output = dest; /* check for a valid global RNG context */
PORT_Assert(rng != NULL); if (rng == NULL) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure;
} /* FIPS limits the amount of entropy available in a single request */ if (len > PRNG_MAX_REQUEST_SIZE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure;
} /* --- LOCKED --- */
PZ_Lock(rng->lock); /* Check the amount of seed data in the generator. If not enough, * don't produce any data.
*/ if (rng->reseed_counter[0] >= RESEED_VALUE) {
rv = prng_reseed_test(rng, NULL, 0, NULL, 0);
PZ_Unlock(rng->lock); if (rv != SECSuccess) { return rv;
}
RNG_SystemInfoForRNG();
PZ_Lock(rng->lock);
} /* * see if we have enough bytes to fulfill the request.
*/ if (len <= rng->dataAvail) {
memcpy(output, rng->data + ((sizeof(rng->data)) - rng->dataAvail), len);
memset(rng->data + ((sizeof(rng->data)) - rng->dataAvail), 0, len);
rng->dataAvail -= len;
rv = SECSuccess; /* if we are asking for a small number of bytes, cache the rest of
* the bytes */
} elseif (len < sizeof(rng->data)) {
rv = prng_generateNewBytes(rng, rng->data, sizeof(rng->data),
rng->additionalAvail ? rng->additionalDataCache : NULL,
rng->additionalAvail);
rng->additionalAvail = 0; if (rv == SECSuccess) {
memcpy(output, rng->data, len);
memset(rng->data, 0, len);
rng->dataAvail = (sizeof(rng->data)) - len;
} /* we are asking for lots of bytes, just ask the generator to pass them */
} else {
rv = prng_generateNewBytes(rng, output, len,
rng->additionalAvail ? rng->additionalDataCache : NULL,
rng->additionalAvail);
rng->additionalAvail = 0;
}
PZ_Unlock(rng->lock); /* --- UNLOCKED --- */ return rv;
}
/* ** Generate some random bytes, using the global random number generator ** object.
*/
SECStatus
RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
{ return prng_GenerateGlobalRandomBytes(globalrng, dest, len);
}
void
RNG_RNGShutdown(void)
{ /* check for a valid global RNG context */
PORT_Assert(globalrng != NULL); if (globalrng == NULL) { /* Should set a "not initialized" error code. */
PORT_SetError(SEC_ERROR_NO_MEMORY); return;
} /* clear */
prng_freeRNGContext(globalrng);
globalrng = NULL; /* reset the callonce struct to allow a new call to RNG_RNGInit() */
coRNGInit = pristineCallOnce;
}
/* * Test case interface. used by fips testing and power on self test
*/ /* make sure the test context is separate from the global context, This * allows us to test the internal random number generator without losing
* entropy we may have previously collected. */
RNGContext testContext;
/* * Test vector API. Use NIST SP 800-90 general interface so one of the * other NIST SP 800-90 algorithms may be used in the future.
*/
SECStatus
PRNGTEST_Instantiate(const PRUint8 *entropy, unsignedint entropy_len, const PRUint8 *nonce, unsignedint nonce_len, const PRUint8 *personal_string, unsignedint ps_len)
{ int bytes_len = entropy_len + nonce_len + ps_len;
PRUint8 *bytes = NULL;
SECStatus rv;
/********************************************/ /* First test instantiate error path. */ /* In this case we supply enough entropy, */ /* but not enough seed. This will trigger */ /* the code that checks for a entropy */ /* source failure. */ /********************************************/
rng_status = PRNGTEST_Instantiate(entropy, 256 / PR_BITS_PER_BYTE,
NULL, 0, NULL, 0); if (rng_status == SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} /* we failed with the proper error code, we can continue */
/********************************************/ /* Generate random bytes with a known seed. */ /********************************************/
rng_status = PRNGTEST_Instantiate(entropy, sizeof(entropy),
NULL, 0, NULL, 0); if (rng_status != SECSuccess) { /* Error set by PRNGTEST_Instantiate */ return SECFailure;
}
rng_status = PRNGTEST_Generate(result, sizeof(rng_known_result), NULL, 0); if ((rng_status != SECSuccess) ||
(PORT_Memcmp(result, rng_known_result, sizeof(rng_known_result)) != 0)) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
}
rng_status = PRNGTEST_Reseed(reseed_entropy, sizeof(reseed_entropy),
additional_input, sizeof(additional_input)); if (rng_status != SECSuccess) { /* Error set by PRNG_Reseed */
PRNGTEST_Uninstantiate(); return SECFailure;
}
rng_status = PRNGTEST_Generate(result, sizeof(rng_reseed_result), NULL, 0); if ((rng_status != SECSuccess) ||
(PORT_Memcmp(result, rng_reseed_result, sizeof(rng_reseed_result)) != 0)) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} /* This magic forces the reseed count to it's max count, so we can see if
* PRNGTEST_Generate will actually when it reaches it's count */
rng_status = PRNGTEST_Reseed(NULL, 0, NULL, 0); if (rng_status != SECSuccess) {
PRNGTEST_Uninstantiate(); /* Error set by PRNG_Reseed */ return SECFailure;
} /* This generate should now reseed */
rng_status = PRNGTEST_Generate(result, sizeof(rng_reseed_result), NULL, 0); if ((rng_status != SECSuccess) || /* NOTE we fail if the result is equal to the no_reseed_result. * no_reseed_result is the value we would have gotten if we didn't
* do an automatic reseed in PRNGTEST_Generate */
(PORT_Memcmp(result, rng_no_reseed_result, sizeof(rng_no_reseed_result)) == 0)) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} /* make sure reseed fails when we don't supply enough entropy */
rng_status = PRNGTEST_Reseed(reseed_entropy, 4, NULL, 0); if (rng_status == SECSuccess) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} if (PORT_GetError() != SEC_ERROR_NEED_RANDOM) {
PRNGTEST_Uninstantiate();
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
}
rng_status = PRNGTEST_Uninstantiate(); if (rng_status != SECSuccess) { /* Error set by PRNG_Uninstantiate */ return rng_status;
} /* make sure uninstantiate fails if the contest is not initiated (also tests
* if the context was cleared in the previous Uninstantiate) */
rng_status = PRNGTEST_Uninstantiate(); if (rng_status == SECSuccess) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure;
} if (PORT_GetError() != SEC_ERROR_LIBRARY_FAILURE) { return rng_status;
}
return SECSuccess;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.39 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.