/* * 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; }
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; }
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]); } }
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); }
/* * 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; }
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; }
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; }
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); } }
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; }
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); }
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; }
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 }
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; }
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; }
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; }