int ctr_generate(RAND_DRBG *drbg, unsigned char *out, size_t outlen, const unsigned char *adin, size_t adinlen) { RAND_DRBG_CTR *ctr = &drbg->ctr; if (adin != NULL && adinlen != 0) { ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0); /* This means we reuse derived value */ if (drbg->flags & RAND_DRBG_FLAG_CTR_USE_DF) { adin = NULL; adinlen = 1; } } else { adinlen = 0; } for ( ; ; ) { inc_128(ctr); if (outlen < 16) { /* Use K as temp space as it will be updated */ AES_encrypt(ctr->V, ctr->K, &ctr->ks); memcpy(out, ctr->K, outlen); break; } AES_encrypt(ctr->V, out, &ctr->ks); out += 16; outlen -= 16; if (outlen == 0) break; } ctr_update(drbg, adin, adinlen, NULL, 0, NULL, 0); return 1; }
static void ctr_Update(DRBG_CTX *dctx, const unsigned char *in1, size_t in1len, const unsigned char *in2, size_t in2len, const unsigned char *nonce, size_t noncelen) { DRBG_CTR_CTX *cctx = &dctx->d.ctr; /* ks is already setup for correct key */ inc_128(cctx); AES_encrypt(cctx->V, cctx->K, &cctx->ks); /* If keylen longer than 128 bits need extra encrypt */ if (cctx->keylen != 16) { inc_128(cctx); AES_encrypt(cctx->V, cctx->K + 16, &cctx->ks); } inc_128(cctx); AES_encrypt(cctx->V, cctx->V, &cctx->ks); /* If 192 bit key part of V is on end of K */ if (cctx->keylen == 24) { memcpy(cctx->V + 8, cctx->V, 8); memcpy(cctx->V, cctx->K + 24, 8); } if (dctx->flags & DRBG_FLAG_CTR_USE_DF) { /* If no input reuse existing derived value */ if (in1 || nonce || in2) ctr_df(cctx, in1, in1len, nonce, noncelen, in2, in2len); /* If this a reuse input in1len != 0 */ if (in1len) ctr_XOR(cctx, cctx->KX, dctx->seedlen); } else { ctr_XOR(cctx, in1, in1len); ctr_XOR(cctx, in2, in2len); } AES_set_encrypt_key(cctx->K, dctx->strength, &cctx->ks); #if 0 fprintf(stderr, "K+V after update is:\n"); BIO_dump_fp(stderr, cctx->K, cctx->keylen); BIO_dump_fp(stderr, cctx->V, 16); #endif }
/* * NB the no-df Update in SP800-90A specifies a constant input length * of seedlen, however other uses of this algorithm pad the input with * zeroes if necessary and have up to two parameters XORed together, * so we handle both cases in this function instead. */ static void ctr_update(RAND_DRBG *drbg, const unsigned char *in1, size_t in1len, const unsigned char *in2, size_t in2len, const unsigned char *nonce, size_t noncelen) { RAND_DRBG_CTR *ctr = &drbg->ctr; /* ks is already setup for correct key */ inc_128(ctr); AES_encrypt(ctr->V, ctr->K, &ctr->ks); /* If keylen longer than 128 bits need extra encrypt */ if (ctr->keylen != 16) { inc_128(ctr); AES_encrypt(ctr->V, ctr->K + 16, &ctr->ks); } inc_128(ctr); AES_encrypt(ctr->V, ctr->V, &ctr->ks); /* If 192 bit key part of V is on end of K */ if (ctr->keylen == 24) { memcpy(ctr->V + 8, ctr->V, 8); memcpy(ctr->V, ctr->K + 24, 8); } if (drbg->flags & RAND_DRBG_FLAG_CTR_USE_DF) { /* If no input reuse existing derived value */ if (in1 != NULL || nonce != NULL || in2 != NULL) ctr_df(ctr, in1, in1len, nonce, noncelen, in2, in2len); /* If this a reuse input in1len != 0 */ if (in1len) ctr_XOR(ctr, ctr->KX, drbg->seedlen); } else { ctr_XOR(ctr, in1, in1len); ctr_XOR(ctr, in2, in2len); } AES_set_encrypt_key(ctr->K, drbg->strength, &ctr->ks); }
static int drbg_ctr_generate(DRBG_CTX *dctx, unsigned char *out, size_t outlen, const unsigned char *adin, size_t adinlen) { DRBG_CTR_CTX *cctx = &dctx->d.ctr; if (adin && adinlen) { ctr_Update(dctx, adin, adinlen, NULL, 0, NULL, 0); /* This means we reuse derived value */ if (dctx->flags & DRBG_FLAG_CTR_USE_DF) { adin = NULL; adinlen = 1; } } else adinlen = 0; for (;;) { inc_128(cctx); if (!(dctx->flags & DRBG_FLAG_TEST) && !dctx->lb_valid) { AES_encrypt(cctx->V, dctx->lb, &cctx->ks); dctx->lb_valid = 1; continue; } if (outlen < 16) { /* Use K as temp space as it will be updated */ AES_encrypt(cctx->V, cctx->K, &cctx->ks); if (!fips_drbg_cprng_test(dctx, cctx->K)) return 0; memcpy(out, cctx->K, outlen); break; } AES_encrypt(cctx->V, out, &cctx->ks); if (!fips_drbg_cprng_test(dctx, out)) return 0; out += 16; outlen -= 16; if (outlen == 0) break; } ctr_Update(dctx, adin, adinlen, NULL, 0, NULL, 0); return 1; }