示例#1
0
文件: drbg.c 项目: emaldona/nss
static PRStatus
rng_init(void)
{
    PRUint8 bytes[PRNG_SEEDLEN * 2]; /* entropy + nonce */
    unsigned int numBytes;
    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 */
        numBytes = (unsigned int)RNG_SystemRNG(bytes, sizeof bytes);
        PORT_Assert(numBytes == 0 || numBytes == sizeof bytes);
        if (numBytes != 0) {
            /* 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, numBytes);
            } else {
                rv = prng_reseed_test(globalrng, bytes, numBytes, NULL, 0);
            }
            memset(bytes, 0, numBytes);
        } 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;
}
示例#2
0
/*
** 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 */
    } else if (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;
}
示例#3
0
/*
** Update the global random number generator with more seeding
** material.
*/
SECStatus 
RNG_RandomUpdate(const void *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);

#if defined(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.
     */

    PR_STATIC_ASSERT(sizeof(size_t) > 4);

    if (bytes > PRNG_MAX_ADDITIONAL_BYTES) {
	bytes = PRNG_MAX_ADDITIONAL_BYTES;
    }
#else
    PR_STATIC_ASSERT(sizeof(size_t) <= 4);
#endif

    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, (unsigned int) bytes);
    /* if we aren't going to fill or overflow the buffer, just cache it */
    } else if (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 = ((unsigned char *)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;
}