예제 #1
0
/*
 * NIST SP 800-90 March 2007
 * 10.2.1.2 The Update Function
 */
static int
drbg_update(struct ccdrbg_nistctr_state * drbg, const uint32_t *provided_data)
{
	uint32_t		i;
    uint32_t		temp[CCADRBG_TEMPLEN_INTS(drbg)];
	uint32_t		*output_block;
	
    /* Clear temp buffer */
    cc_clear(sizeof(temp),temp);

	/* 2. while (len(temp) < seedlen) do */
	for (output_block = temp; output_block < &temp[CCADRBG_SEEDLEN_INTS(drbg)];
		output_block += CCADRBG_OUTLEN_INTS(drbg))
	{
		/* 2.1 V = (V + 1) mod 2^outlen */
#if NONFIPSINC128
		(drbg->inc128)(drbg, drbg->V);
#else
		increment_bigend_128(drbg, drbg->V);
#endif
		/* 2.2 output_block = Block_Encrypt(K, V) */

        drbg->ecb->ecb(drbg->key, 1, drbg->V, output_block);
    }

	// check that the two halves are not the same.
    unsigned char* tempPtr = (unsigned char*)temp;
	if (!cc_cmp_safe(CCADRBG_KEYLEN(drbg), tempPtr, &tempPtr[CCADRBG_KEYLEN(drbg)]))
    {
		cc_clear(sizeof(temp), temp);
		return CCDRBG_STATUS_ERROR;
	}

	/* 3 temp is already of size seedlen (CCADRBG_SEEDLEN_INTS) */

	/* 4 (part 1) temp = temp XOR provided_data */
	for (i = 0; i < CCADRBG_KEYLEN_INTS(drbg); ++i)
		temp[i] ^= *provided_data++;

	/* 5 Key = leftmost keylen bits of temp */
    drbg->ecb->init(drbg->ecb, drbg->key, CCADRBG_KEYLEN(drbg), &temp[0]);
	/* 4 (part 2) combined with 6 V = rightmost outlen bits of temp */
	for (i = 0; i < CCADRBG_OUTLEN_INTS(drbg); ++i)
		drbg->V[i] = temp[CCADRBG_KEYLEN_INTS(drbg) + i] ^ *provided_data++;
		
	cc_clear(sizeof(temp), temp);
	return CCDRBG_STATUS_OK;
}
예제 #2
0
static int
generate_block(struct ccdrbg_nistctr_state * drbg, uint32_t	*blk)
{
    int rc;
    uint8_t	temp2[CCADRBG_BLOCKSIZE(drbg)];

    // the folowing lines are performed as rquested in Radar 19129408
    if (drbg->strictFIPS)
    {
        rc = gen_block(drbg, temp2); cc_require(rc==CCDRBG_STATUS_OK, errOut);
        rc = gen_block(drbg, blk);   cc_require(rc==CCDRBG_STATUS_OK, errOut);
        rc = cc_cmp_safe(CCADRBG_BLOCKSIZE(drbg), blk, temp2);
        rc = (rc==0) ? CCDRBG_STATUS_ABORT: CCDRBG_STATUS_OK;
errOut:
        cc_clear(CCADRBG_BLOCKSIZE(drbg), temp2);

    }else{
        rc=gen_block(drbg, blk);
    }

    if(rc==CCDRBG_STATUS_ABORT){
        //The world as we know it has come to an end
        //the DRBG data structure is zeroized. subsequent calls to
        //DRBG ends up in NULL dereferencing and/or unpredictable state.
        //catastrophic error in SP 800-90A
        done((struct ccdrbg_state *)drbg);
        cc_abort(NULL);
    }
    
    return rc;

}
예제 #3
0
static void
df_initialize(struct ccdrbg_nistctr_state * drbg)
{
	uint32_t		i;
	uint8_t			K[CCADRBG_KEYLEN(drbg)];
	uint32_t		IV[CCADRBG_OUTLEN_INTS(drbg)];

	/* [8] K = Leftmost keylen bits of 0x00010203 ... 1D1E1F */
	for (i = 0; i < sizeof(K); ++i)
		K[i] = (uint8_t)i;

    drbg->ecb->init(drbg->ecb, drbg->df_key, sizeof(K), K);

	/*
	 * Precompute the partial BCC result from encrypting the IVs:
	 *     encryptedIV[i] = BCC(K, IV(i))
	 */

	/* [7] i = 0 */
	/* [9.1] IV = i || 0^(outlen - len(i)) */
	cc_clear(sizeof(IV),&IV[0]);

		/* [9.3] i = i + 1 */
	for (i = 0; i < CCADRBG_TEMPLEN_BLOCKS(drbg); ++i)
	{
		/* [9.1] IV = i || 0^(outlen - len(i)) */
		IV[0] = CC_H2BE32(i);

		/* [9.2] temp = temp || BCC(K, (IV || S))  (the IV part, at least) */
		bcc(drbg, &IV[0], 1, (uint32_t *)&drbg->encryptedIV[i*CCADRBG_OUTLEN(drbg)+0]);
	}
}
예제 #4
0
static void
bcc(struct ccdrbg_nistctr_state *drbg, const uint32_t *data, unsigned long n, uint32_t *output_block)
{
	uint32_t	*chaining_value = output_block;

	/* [1] chaining_value = 0^outlen */
	cc_clear(CCADRBG_OUTLEN(drbg),&chaining_value[0]);

	bcc_update(drbg, data, n, output_block);
}
예제 #5
0
/*
 * NIST SP 800-90 March 2007
 * 10.2.1.4.2 The Process Steps for Reseeding When a Derivation
 *            Function is Used
 */
static int
reseed(struct ccdrbg_state *rng,
    unsigned long entropyLength, const void *entropy,
    unsigned long additionalLength, const void *additional)
{
	int         err;
    uint32_t    count;
	const char	*input_string[2];
	uint32_t	length[2];
    struct ccdrbg_nistctr_state *drbg=(struct ccdrbg_nistctr_state *)rng;
	uint32_t	seed_material[CCADRBG_SEEDLEN_INTS(drbg)];

    
    err =validate_inputs(drbg, entropyLength, additionalLength, 0); if(err!=CCDRBG_STATUS_OK) return err;
    
    if(drbg->use_df) {
        /* [1] seed_material = entropy || additional */
        input_string[0] = entropy;
        /* typecast: guaranteed to fit by the above checks */
        length[0] = (uint32_t)entropyLength;
        count = 1;

        if (additional && additionalLength)
        {
            input_string[count] = additional;
            /* typecast: guaranteed to fit by above checks */
            length[count] = (uint32_t)additionalLength;
            ++count;
        }

        /* [2] seed_material = Block_Cipher_df(seed_material, seedlen) */
        err = df(drbg, input_string, length, count,
                (uint8_t *)seed_material, sizeof(seed_material));
        if (err)
            return err;
    } else {
        cc_clear(sizeof(seed_material),seed_material);
        cc_assert(additionalLength==0 || additionalLength==sizeof(seed_material)); //additionalLength is validated above
        CC_MEMCPY(seed_material, additional, additionalLength);
        cc_xor(CCADRBG_SEEDLEN(drbg), seed_material, seed_material, entropy);
    }

	/* [3] (Key, V) = Update(seed_material, Key, V) */
	if (drbg_update(drbg, seed_material))
	{
		return CCDRBG_STATUS_PARAM_ERROR;
	}

	/* [4] reseed_counter = 1 */
	drbg->reseed_counter = 1;

	return CCDRBG_STATUS_OK;
}
예제 #6
0
int ccnistkdf_fb_hmac(const struct ccdigest_info *di, int use_counter,
                      size_t kdkLen, const void *kdk,
                      size_t labelLen, const void *label,
                      size_t contextLen, const void *context,
                      size_t ivLen, const void *iv,
                      size_t dkLen, void *dk) {
    size_t fixedDataLen = labelLen + contextLen + 5;
    uint8_t fixedData[fixedDataLen];
    construct_fixed_data(labelLen, label, contextLen, context, dkLen, fixedData);
    int retval = ccnistkdf_fb_hmac_fixed(di, use_counter, kdkLen, kdk, fixedDataLen, fixedData, ivLen, iv, dkLen, dk);
    cc_clear(fixedDataLen,fixedData);
    return retval;
}
예제 #7
0
int ccnistkdf_fb_hmac_fixed(const struct ccdigest_info *di, int use_counter,
                      size_t kdkLen, const void *kdk,
                      size_t fixedDataLen, const void *fixedData,
                      size_t ivLen, const void *iv,
                      size_t dkLen, void *dk) {
    size_t h = di->output_size;
    size_t n = cc_div_ceiling(dkLen, h);
    uint8_t result_buf[n*h];
    uint8_t *result = result_buf;
    const uint8_t *iv_local = iv;
    uint8_t iv_local_len = ivLen;
    
    if(n > UINT32_MAX) return -1;
    if(kdkLen == 0 || kdk == NULL) return -1;
    if(dkLen == 0 || dk == NULL) return -1;
    
    use_counter = (use_counter) ? 1: 0;
    
    cchmac_di_decl(di, hc);
    cchmac_state_cache(di, istate);
    cchmac_init(di, hc, kdkLen, kdk);
    cchmac_cache_state(di, hc, istate);
    
    for(size_t i = 1; i <= n; i++, result += h) {
        F(di, hc, istate, iv_local_len, iv_local, i*use_counter, fixedDataLen, fixedData, result);
        iv_local = result;
        iv_local_len = h;
    }
    
    CC_MEMCPY(dk, result_buf, dkLen);
    cc_clear(n*h,result_buf);
	cchmac_di_clear(di, hc);
	cc_clear(di->state_size, istate);
    
    return 0;
}
예제 #8
0
static void
df_bcc_final(struct ccdrbg_nistctr_state * drbg, uint32_t *temp)
{
	unsigned long idx;
	_CCADRBG_BCC		*ctx = &drbg->bcc;
	static const char	endmark[] = { (char)0x80 };
	uint8_t	*S = (uint8_t *)ctx->S;

	df_bcc_update(drbg, endmark, sizeof(endmark), temp);

	idx = ctx->index;
	if (idx)
	{
		cc_clear(CCADRBG_OUTLEN(drbg) - idx,&S[idx]);

		/* [9.2] BCC */
		bcc_update(drbg, (uint32_t *)&S[0], 1, temp);
	}
}
예제 #9
0
static void
done(struct ccdrbg_state *rng)
{

    struct ccdrbg_nistctr_state *drbg=(struct ccdrbg_nistctr_state *)rng;
    unsigned long bs=drbg->ecb->block_size;
    cc_clear((((drbg->keylen + bs * 2-1)/bs)*bs),drbg->encryptedIV);
    cc_clear(bs, drbg->V);
    cc_clear(drbg->keylen + bs, drbg->nullInput);
    cc_clear(bs, drbg->bcc.S);
    cc_clear(drbg->ecb->size, drbg->key);
    cc_clear(drbg->ecb->size, drbg->df_key);

    cc_clear(sizeof(*drbg), drbg);

    // Possibly superfluous, but NIST wants it.
    drbg->reseed_counter = UINT32_MAX;
}
예제 #10
0
void cccmac_final(const struct ccmode_cbc *cbc, cccmac_ctx_t ctx,
                  size_t nbytes, const void *in, void *out) {
    size_t nblocks = nbytes / CMAC_BLOCKSIZE;
    size_t final_bytes = nbytes % CMAC_BLOCKSIZE;
    uint8_t final_buf[CMAC_BLOCKSIZE];
    void *subkey = cccmac_k2(ctx);
    
    cc_clear(CMAC_BLOCKSIZE, final_buf);
    if(nbytes && final_bytes == 0) {
        nblocks--;
        final_bytes = CMAC_BLOCKSIZE;
        subkey = cccmac_k1(ctx);
    } else {
        final_buf[final_bytes] = 0x80;
    }
    CC_MEMCPY(final_buf, ((const uint8_t *)in) + nblocks*CMAC_BLOCKSIZE, final_bytes);
    cc_xor(CMAC_BLOCKSIZE, final_buf, final_buf, subkey);
    cccmac_compress(cbc, ctx, nblocks, in, out);
    cccmac_compress(cbc, ctx, 1, final_buf, out);
}
예제 #11
0
CC_NO_SANITIZE static void
stack_clear(size_t size)
{
    uint32_t array[size];
    cc_clear(sizeof(array),array);
}
int
ccecies_encrypt_gcm_composite(ccec_pub_ctx_t public_key,
                    const ccecies_gcm_t ecies,
                    uint8_t *exported_public_key, /* output - length from ccecies_pub_key_size */
                    uint8_t *ciphertext,          /* output - length same as plaintext_len */
                    uint8_t *mac_tag,             /* output - length ecies->mac_length */
                    size_t plaintext_len,   const uint8_t *plaintext,
                    size_t sharedinfo1_byte_len, const void *sharedinfo_1,
                    size_t sharedinfo2_byte_len, const void *sharedinfo_2
)
{
    int status=-1;

    // Contexts:
    ccec_full_ctx_decl_cp(ccec_ctx_cp(public_key), ephemeral_key);
    size_t   skey_size = ccec_cp_prime_size(ccec_ctx_cp(public_key));
    uint8_t  skey[skey_size];
    const struct ccmode_gcm *gcm_encrypt=ecies->gcm;
    ccgcm_ctx_decl(gcm_encrypt->size,gcm_ctx);
    size_t exported_public_key_size;

    // 1) Generate ephemeral EC key pair
    cc_assert(ecies->rng!=NULL);
    cc_require(ccecdh_generate_key(ccec_ctx_cp(public_key), ecies->rng, ephemeral_key)==0,errOut);

#if CC_DEBUG_ECIES
    ccec_print_full_key("Ephemeral key",ephemeral_key);
#endif

    // 2) ECDH with input public key
    cc_require(ccecdh_compute_shared_secret(ephemeral_key, public_key, &skey_size, skey,ecies->rng)==0,errOut);

#if CC_DEBUG_ECIES
    cc_print("Shared secret key",skey_size,skey);
#endif

    // 3) Export ephemeral public key
    cc_require( ccecies_export(0, ecies->options, exported_public_key, ephemeral_key)==0, errOut);

    // 4) Derive Enc / Mac key
    // Hash(skey|00000001|sharedinfo_1)
    cc_assert(ecies->key_length<=skey_size);
    exported_public_key_size=ccecies_pub_key_size(ephemeral_key,ecies);
    if (ECIES_EPH_PUBKEY_IN_SHAREDINFO1 == (ecies->options & ECIES_EPH_PUBKEY_IN_SHAREDINFO1))
    {   // use ephemeral public key as shared info 1
        cc_require(ccansikdf_x963(ecies->di,
                                  skey_size,skey,
                                  exported_public_key_size,exported_public_key,
                                  ecies->key_length,skey)==0,errOut);
    }
    else
    {
        cc_require(ccansikdf_x963(ecies->di,
                                  skey_size,skey,
                                  sharedinfo1_byte_len,sharedinfo_1,
                                  ecies->key_length,skey)==0,errOut);
    }

#if CC_DEBUG_ECIES
    cc_print("Cipher key",ecies->key_length,skey);
#endif

    // 5) Encrypt
    ccgcm_init(gcm_encrypt, gcm_ctx,ecies->key_length,skey);
    ccgcm_set_iv(gcm_encrypt,gcm_ctx,sizeof(ecies_iv_data),ecies_iv_data);
    if ((sharedinfo_2!=NULL) && (sharedinfo2_byte_len>0)) {
        ccgcm_gmac(gcm_encrypt,gcm_ctx,sharedinfo2_byte_len,sharedinfo_2);
    }
    else
    {
        ccgcm_gmac(gcm_encrypt,gcm_ctx,0,NULL);
    }
    ccgcm_update(gcm_encrypt,gcm_ctx,
                 plaintext_len,plaintext,
                 ciphertext);

#if CC_DEBUG_ECIES
    cc_print("Encrypted message",plaintext_len,ciphertext);
#endif

    // 6) Mac (with SharedInfo 2)
    // sec1, p51: recommended: SharedInfo2 ended in a counter giving its length.
    ccgcm_finalize(gcm_encrypt,gcm_ctx,ecies->mac_length,mac_tag);
#if CC_DEBUG_ECIES
    cc_print("Mac Tag",ecies->mac_length,mac_tag);
#endif

    // Success
    status=0;

errOut:
    // Clear key material info
    ccgcm_ctx_clear(gcm_encrypt->size,gcm_ctx);
    cc_clear(sizeof(skey),skey);
    ccec_full_ctx_clear_cp(ccec_ctx_cp(public_key), ephemeral_key);
    return status;
}
예제 #13
0
static void done(struct ccdrbg_state *drbg)
{
    struct ccdrbg_nisthmac_state *state=(struct ccdrbg_nisthmac_state *)drbg;
    cc_clear(sizeof(struct ccdrbg_nisthmac_state), state); //clear v, key as well as internal variables
}
예제 #14
0
static int nistctr_init(const struct ccdrbg_nistctr_custom *custom, struct ccdrbg_nistctr_state *drbg, char *keys,
                        const void* entropy, unsigned long entropyLength,
                        const void* nonce, unsigned long nonceLength,
                        const void* ps, unsigned long psLength
                        )
{
	int         err;
    uint32_t    count;
    char *buf;
    
    drbg->ecb = custom->ecb;
    drbg->keylen = custom->keylen;
    buf=keys;
    
    unsigned long bs=drbg->ecb->block_size;
    drbg->encryptedIV = (uint8_t *)buf; buf+=((drbg->keylen+bs*2-1)/bs)*bs;
    drbg->V = (uint32_t *)buf; buf+=bs; //CCADRBG_OUTLEN(drbg);
    drbg->nullInput = (uint32_t *)buf; buf+=drbg->keylen+bs; //CCADRBG_SEEDLEN(drbg);
    drbg->bcc.S = (uint32_t *)buf; buf+=bs; //CCADRBG_OUTLEN(drbg);
    drbg->key = (ccecb_ctx *)buf; buf+=drbg->ecb->size;
    drbg->df_key = (ccecb_ctx *)buf;

	// First initialize the struct
	drbg->strictFIPS = custom->strictFIPS;
    drbg->use_df = custom->use_df;

#if NONFIPSINC128
	if (strictFIPS)
		drbg->inc128 = increment_bigend_128;
	else
		drbg->inc128 = increment_bigend_128_NOFIPS;
#endif

	for (count = 0; count < CCADRBG_SEEDLEN_INTS(drbg); count++)
		drbg->nullInput[count] = 0;

	// Reseed counter is set in [6] below.
	// V is set in [4] and [5]

	// Initialize the derivation function
	//
    
    //nonce is not checked, caller needs to make sure nonce is right as per NIST 800-90A section 8.6.7
    int rc=validate_inputs(drbg, entropyLength, 0, psLength);
    if(rc!=CCDRBG_STATUS_OK){
        done((struct ccdrbg_state *)drbg);
        return rc;
    }
    
    uint8_t		K[CCADRBG_KEYLEN(drbg)];
    uint32_t	seed_material[CCADRBG_SEEDLEN_INTS(drbg)];

    if(drbg->use_df) {
        uint32_t    length[3];
        const char	*input_string[3];

         df_initialize(drbg);

        /* [1] seed_material = entropy || nonce || ps */

        input_string[0] = entropy;
        /* typecast: guaranteed to fit by above checks */
        length[0] = (uint32_t)entropyLength;

        input_string[1] = nonce;
        /* typecast: guaranteed to fit by above checks */
        length[1] = (uint32_t)nonceLength;

        count = 2;
        if (ps && psLength)
        {
            input_string[count] = ps;
            /* typecast: guaranteed to fit by above checks */
            length[count] = (uint32_t) psLength;
            ++count;
        }
            /* [2] seed_material = Block_Cipher_df(seed_material, seedlen) */
        err = df(drbg, input_string, length, count,
                 (uint8_t *)seed_material, sizeof(seed_material));
        if (err)
		{
			cc_clear(sizeof(seed_material),seed_material);
			done((struct ccdrbg_state *)drbg);
			return err;
		}
            
    } else {
        cc_clear(sizeof(seed_material),seed_material);
        cc_assert(psLength==0 || psLength==sizeof(seed_material)); //pslength is validated above
        CC_MEMCPY(seed_material, ps, psLength);
        cc_xor(CCADRBG_SEEDLEN(drbg), seed_material, seed_material, entropy);
    }

	/* [3] Key = 0^keylen */
	cc_clear(sizeof(K), K);
    drbg->ecb->init(drbg->ecb, drbg->key, sizeof(K), K);

	/* [4] V = 0^outlen */
    cc_clear(CCADRBG_OUTLEN(drbg),drbg->V);

	/* [5] (Key, V) = Update(seed_material, Key, V) */
	if (drbg_update(drbg, seed_material))
	{
		cc_clear(sizeof(seed_material),seed_material);
		done((struct ccdrbg_state *)drbg);
		return CCDRBG_STATUS_PARAM_ERROR;
	}
	cc_clear(sizeof(seed_material),seed_material);

	/* [6] reseed_counter = 1 */
	drbg->reseed_counter = 1;

	return CCDRBG_STATUS_OK;
}
예제 #15
0
static int
generate(struct ccdrbg_state *rng,
         unsigned long dataOutLength, void *dataOut,
         unsigned long additionalLength, const void *additional)
{
    int rc = CCDRBG_STATUS_OK;
    unsigned long i;
    unsigned long len;
    uint8_t		*p;
    uint32_t	*temp;
    const char	*input_string[1];
    uint32_t	length[1];
    struct ccdrbg_nistctr_state *drbg = (struct ccdrbg_nistctr_state *)rng;
    uint32_t	buffer[CCADRBG_OUTLEN(drbg)];
    uint32_t	additional_buffer[CCADRBG_SEEDLEN_INTS(drbg)];
    unsigned long blocks = dataOutLength / CCADRBG_OUTLEN(drbg);

    /* [1] If reseed_counter > reseed_interval ... */
    rc = validate_gen_params(drbg, dataOutLength, (additional !=NULL)?additionalLength:0); cc_require(rc==CCDRBG_STATUS_OK, errOut);

    /* [2] If (addional_input != Null), then */
    if (additional && additionalLength)
    {
        if(drbg->use_df) {
            input_string[0] = additional;
            /* typecast: guaranteed to fit by the checks above */
            length[0] = (uint32_t)additionalLength;
            /* [2.1] additional = Block_Cipher_df(additional, seedlen) */
            rc = df(drbg, input_string, length, 1,
                    (uint8_t *)additional_buffer, sizeof(additional_buffer));
            cc_require(rc==CCDRBG_STATUS_OK, errOut);
        } else {
            cc_clear(sizeof(additional_buffer), additional_buffer);
            cc_assert(additionalLength==0 || additionalLength==sizeof(additional_buffer)); //additionalLength is validated above
            CC_MEMCPY(additional_buffer, additional, additionalLength);
        }

        /* [2.2] (Key, V) = Update(additional, Key, V) */
        rc=drbg_update(drbg, additional_buffer); cc_require(rc==CCDRBG_STATUS_OK, errOut);
    }

    if (blocks && check_int_alignment(dataOut))
    {
        /* [3] temp = Null */
        temp = (uint32_t *)dataOut;
        for (i = 0; i < blocks; ++i)
        {
            // Here is the conundrum that is FIPS.
            // In order to test the DRBG for CAVS one must NOT set strictFIPS
            // and thus not have a compliant DRBG.  That is the only way to
            // ensure that the CAVS test will pass.  On the other hand the
            // 'normal' usage of the DRBG MUST set the strictFIPS flag.  So
            // that which is used by our customers is NOT what was tested.
            rc = generate_block(drbg, temp); cc_require(rc==CCDRBG_STATUS_OK, errOut);
            temp += CCADRBG_OUTLEN_INTS(drbg);
            dataOutLength -= CCADRBG_OUTLEN(drbg);
        }

        dataOut = (uint8_t *)temp;
    }

    /* [3] temp = Null */
    temp = buffer;

    len = CCADRBG_OUTLEN(drbg);

    /* [4] While (len(temp) < requested_number_of_bits) do: */
    p = dataOut;
    while (dataOutLength > 0)
    {
        // See note above.
        rc = generate_block(drbg, temp); cc_require(rc==CCDRBG_STATUS_OK, errOut);
        if (dataOutLength < CCADRBG_OUTLEN(drbg))
            len = dataOutLength;

        memcpy(p, temp, len);

        p += len;
        dataOutLength -= len;
    }

    /* [6] (Key, V) = Update(additional, Key, V) */
    rc = drbg_update(drbg, additional && additionalLength ? &additional_buffer[0] :
                     &drbg->nullInput[0]);
    cc_require(rc==CCDRBG_STATUS_OK, errOut);
    
    /* [7] reseed_counter = reseed_counter + 1 */
    ++drbg->reseed_counter;
    
errOut:
    cc_clear(sizeof(additional_buffer),additional_buffer);
    return rc;
}
예제 #16
0
static int
df(struct ccdrbg_nistctr_state *drbg, const char *input_string[], uint32_t L[],
    uint32_t input_string_count, uint8_t *output_string, unsigned long N)
{
	unsigned long   j, k, blocks;
    uint64_t        sum_L;
	uint32_t		*temp;
	uint32_t		*X;
	uint32_t		buffer[CCADRBG_TEMPLEN_INTS(drbg)];
    /* declare a key */
    ccecb_ctx_decl(drbg->ecb->size, key);

	/*
	 * NIST SP 800-90 March 2007 10.4.2 states that 512 bits is
	 * the maximum length for the approved block cipher algorithms.
     *
     * Also states that L(sum_L) and N are 32 bits integers.
	 */
    cc_assert(drbg->ecb->block_size<=512/8);
	uint32_t output_buffer[512 / 8 / sizeof(uint32_t)];

	if (N > sizeof(output_buffer) || N < 1)
	{
		ccecb_ctx_clear(drbg->ecb->size, key);
		return -1;
	}
		

	sum_L = 0;
	for (j = 0; j < input_string_count; ++j)
		sum_L += L[j];
    //sum_L is the sum of the all input data-lengths. Since maximum parameters lengths are set properly
    //in the header file, sum_L cannot be more than 32 bits. But a change to those parameters by
    //someone who is not aware of this summation here, would be a disaster.
    //Therefore, we make sum_L 64 bits and we perform the test here.
    if(sum_L > 0xFFFFffff)
        return -1;

	/* [6] temp = Null string */
	temp = buffer;

	/* [9] while len(temp) < keylen + outlen, do */
	for (j = 0; j < CCADRBG_TEMPLEN_BLOCKS(drbg); ++j)
	{
		/* [9.2] temp = temp || BCC(K, (IV || S)) */

		/* Since we have precomputed BCC(K, IV), we start with that... */
		memcpy(&temp[0], &drbg->encryptedIV[j*CCADRBG_OUTLEN(drbg)+0], CCADRBG_OUTLEN(drbg));

        /* typecast: ok, checks above */
		bcc_init(drbg, (uint32_t)sum_L, (uint32_t)N, temp);

		/* Compute the rest of BCC(K, (IV || S)) */
		for (k = 0; k < input_string_count; ++k)
			df_bcc_update(drbg, input_string[k], L[k], temp);

		df_bcc_final(drbg, temp);

		temp += CCADRBG_OUTLEN_INTS(drbg);
	}

	/* [6] temp = Null string */
	temp = buffer;

	/* [10] K = Leftmost keylen bits of temp */
    drbg->ecb->init(drbg->ecb, key, CCADRBG_KEYLEN(drbg), &temp[0]);

	/* [11] X = next outlen bits of temp */
	X = &temp[CCADRBG_KEYLEN_INTS(drbg)];

	/* [12] temp = Null string */
	temp = output_buffer;

	/* [13] While len(temp) < number_of_bits_to_return, do */
	blocks = (N / CCADRBG_OUTLEN(drbg));
	if (N & (CCADRBG_OUTLEN(drbg) - 1))
		++blocks;
	for (j = 0; j < blocks; ++j)
	{
		/* [13.1] X = Block_Encrypt(K, X) */
        drbg->ecb->ecb(key, 1, X, temp);
		X = temp;
		temp += CCADRBG_OUTLEN_INTS(drbg);
	}

	/* [14] requested_bits = Leftmost number_of_bits_to_return of temp */
	memcpy(output_string, output_buffer, N);
	ccecb_ctx_clear(drbg->ecb->size, key);
	cc_clear(sizeof(buffer), buffer);
	cc_clear(sizeof(output_buffer), output_buffer);

	return 0;
}