📄 entropy.c
字号:
zeroize: /* put the entropy we almost extracted back */ add_entropy(ent, total); memset(data, 0, length); memset(digest, 0, sizeof(digest)); if (returned != NULL) *returned = 0; UNLOCK(&ent->lock); return (ISC_R_NOENTROPY);}static voidisc_entropypool_init(isc_entropypool_t *pool) { pool->cursor = RND_POOLWORDS - 1; pool->entropy = 0; pool->pseudo = 0; pool->rotate = 0; memset(pool->pool, 0, RND_POOLBYTES);}static voidisc_entropypool_invalidate(isc_entropypool_t *pool) { pool->cursor = 0; pool->entropy = 0; pool->pseudo = 0; pool->rotate = 0; memset(pool->pool, 0, RND_POOLBYTES);}isc_result_tisc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) { isc_result_t ret; isc_entropy_t *ent; REQUIRE(mctx != NULL); REQUIRE(entp != NULL && *entp == NULL); ent = isc_mem_get(mctx, sizeof(isc_entropy_t)); if (ent == NULL) return (ISC_R_NOMEMORY); /* * We need a lock. */ if (isc_mutex_init(&ent->lock) != ISC_R_SUCCESS) { ret = ISC_R_UNEXPECTED; goto errout; } /* * From here down, no failures will/can occur. */ ISC_LIST_INIT(ent->sources); ent->nextsource = NULL; ent->nsources = 0; ent->mctx = NULL; isc_mem_attach(mctx, &ent->mctx); ent->refcnt = 1; ent->initialized = 0; ent->initcount = 0; ent->magic = ENTROPY_MAGIC; isc_entropypool_init(&ent->pool); *entp = ent; return (ISC_R_SUCCESS); errout: isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); return (ret);}/* * Requires "ent" be locked. */static voiddestroysource(isc_entropysource_t **sourcep) { isc_entropysource_t *source; isc_entropy_t *ent; isc_cbsource_t *cbs; source = *sourcep; *sourcep = NULL; ent = source->ent; ISC_LIST_UNLINK(ent->sources, source, link); ent->nextsource = NULL; REQUIRE(ent->nsources > 0); ent->nsources--; switch (source->type) { case ENTROPY_SOURCETYPE_FILE: if (! source->bad) destroyfilesource(&source->sources.file); break; case ENTROPY_SOURCETYPE_USOCKET: if (! source->bad) destroyusocketsource(&source->sources.usocket); break; case ENTROPY_SOURCETYPE_SAMPLE: samplequeue_release(ent, &source->sources.sample.samplequeue); break; case ENTROPY_SOURCETYPE_CALLBACK: cbs = &source->sources.callback; if (cbs->start_called && cbs->stopfunc != NULL) { cbs->stopfunc(source, cbs->arg); cbs->start_called = ISC_FALSE; } samplequeue_release(ent, &cbs->samplequeue); break; } memset(source, 0, sizeof(isc_entropysource_t)); isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));}static inline isc_boolean_tdestroy_check(isc_entropy_t *ent) { isc_entropysource_t *source; if (ent->refcnt > 0) return (ISC_FALSE); source = ISC_LIST_HEAD(ent->sources); while (source != NULL) { switch (source->type) { case ENTROPY_SOURCETYPE_FILE: case ENTROPY_SOURCETYPE_USOCKET: break; default: return (ISC_FALSE); } source = ISC_LIST_NEXT(source, link); } return (ISC_TRUE);}static voiddestroy(isc_entropy_t **entp) { isc_entropy_t *ent; isc_entropysource_t *source; isc_mem_t *mctx; REQUIRE(entp != NULL && *entp != NULL); ent = *entp; *entp = NULL; LOCK(&ent->lock); REQUIRE(ent->refcnt == 0); /* * Here, detach non-sample sources. */ source = ISC_LIST_HEAD(ent->sources); while (source != NULL) { switch(source->type) { case ENTROPY_SOURCETYPE_FILE: case ENTROPY_SOURCETYPE_USOCKET: destroysource(&source); break; } source = ISC_LIST_HEAD(ent->sources); } /* * If there are other types of sources, we've found a bug. */ REQUIRE(ISC_LIST_EMPTY(ent->sources)); mctx = ent->mctx; isc_entropypool_invalidate(&ent->pool); UNLOCK(&ent->lock); DESTROYLOCK(&ent->lock); memset(ent, 0, sizeof(isc_entropy_t)); isc_mem_put(mctx, ent, sizeof(isc_entropy_t)); isc_mem_detach(&mctx);}voidisc_entropy_destroysource(isc_entropysource_t **sourcep) { isc_entropysource_t *source; isc_entropy_t *ent; isc_boolean_t killit; REQUIRE(sourcep != NULL); REQUIRE(VALID_SOURCE(*sourcep)); source = *sourcep; *sourcep = NULL; ent = source->ent; REQUIRE(VALID_ENTROPY(ent)); LOCK(&ent->lock); destroysource(&source); killit = destroy_check(ent); UNLOCK(&ent->lock); if (killit) destroy(&ent);}isc_result_tisc_entropy_createcallbacksource(isc_entropy_t *ent, isc_entropystart_t start, isc_entropyget_t get, isc_entropystop_t stop, void *arg, isc_entropysource_t **sourcep){ isc_result_t ret; isc_entropysource_t *source; isc_cbsource_t *cbs; REQUIRE(VALID_ENTROPY(ent)); REQUIRE(get != NULL); REQUIRE(sourcep != NULL && *sourcep == NULL); LOCK(&ent->lock); source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); if (source == NULL) { ret = ISC_R_NOMEMORY; goto errout; } source->bad = ISC_FALSE; cbs = &source->sources.callback; ret = samplesource_allocate(ent, &cbs->samplequeue); if (ret != ISC_R_SUCCESS) goto errout; cbs->start_called = ISC_FALSE; cbs->startfunc = start; cbs->getfunc = get; cbs->stopfunc = stop; cbs->arg = arg; /* * From here down, no failures can occur. */ source->magic = SOURCE_MAGIC; source->type = ENTROPY_SOURCETYPE_CALLBACK; source->ent = ent; source->total = 0; memset(source->name, 0, sizeof(source->name)); ISC_LINK_INIT(source, link); /* * Hook it into the entropy system. */ ISC_LIST_APPEND(ent->sources, source, link); ent->nsources++; *sourcep = source; UNLOCK(&ent->lock); return (ISC_R_SUCCESS); errout: if (source != NULL) isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); UNLOCK(&ent->lock); return (ret);}voidisc_entropy_stopcallbacksources(isc_entropy_t *ent) { isc_entropysource_t *source; isc_cbsource_t *cbs; REQUIRE(VALID_ENTROPY(ent)); LOCK(&ent->lock); source = ISC_LIST_HEAD(ent->sources); while (source != NULL) { if (source->type == ENTROPY_SOURCETYPE_CALLBACK) { cbs = &source->sources.callback; if (cbs->start_called && cbs->stopfunc != NULL) { cbs->stopfunc(source, cbs->arg); cbs->start_called = ISC_FALSE; } } source = ISC_LIST_NEXT(source, link); } UNLOCK(&ent->lock);}isc_result_tisc_entropy_createsamplesource(isc_entropy_t *ent, isc_entropysource_t **sourcep){ isc_result_t ret; isc_entropysource_t *source; sample_queue_t *sq; REQUIRE(VALID_ENTROPY(ent)); REQUIRE(sourcep != NULL && *sourcep == NULL); LOCK(&ent->lock); source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); if (source == NULL) { ret = ISC_R_NOMEMORY; goto errout; } sq = &source->sources.sample.samplequeue; ret = samplesource_allocate(ent, sq); if (ret != ISC_R_SUCCESS) goto errout; /* * From here down, no failures can occur. */ source->magic = SOURCE_MAGIC; source->type = ENTROPY_SOURCETYPE_SAMPLE; source->ent = ent; source->total = 0; memset(source->name, 0, sizeof(source->name)); ISC_LINK_INIT(source, link); /* * Hook it into the entropy system. */ ISC_LIST_APPEND(ent->sources, source, link); ent->nsources++; *sourcep = source; UNLOCK(&ent->lock); return (ISC_R_SUCCESS); errout: if (source != NULL) isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t)); UNLOCK(&ent->lock); return (ret);}/* * Add a sample, and return ISC_R_SUCCESS if the queue has become full, * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the * queue was full when this function was called. */static isc_result_taddsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) { if (sq->nsamples >= RND_EVENTQSIZE) return (ISC_R_NOMORE); sq->samples[sq->nsamples] = sample; sq->extra[sq->nsamples] = extra; sq->nsamples++; if (sq->nsamples >= RND_EVENTQSIZE) return (ISC_R_QUEUEFULL); return (ISC_R_SUCCESS);}isc_result_tisc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample, isc_uint32_t extra){ isc_entropy_t *ent; sample_queue_t *sq; unsigned int entropy; isc_result_t result; REQUIRE(VALID_SOURCE(source)); ent = source->ent; LOCK(&ent->lock); sq = &source->sources.sample.samplequeue; result = addsample(sq, sample, extra); if (result == ISC_R_QUEUEFULL) { entropy = crunchsamples(ent, sq); add_entropy(ent, entropy); } UNLOCK(&ent->lock); return (result);}isc_result_tisc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample, isc_uint32_t extra){ sample_queue_t *sq; isc_result_t result; REQUIRE(VALID_SOURCE(source)); REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK); sq = &source->sources.callback.samplequeue; result = addsample(sq, sample, extra); return (result);}voidisc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length, isc_uint32_t entropy){ REQUIRE(VALID_ENTROPY(ent)); LOCK(&ent->lock); entropypool_adddata(ent, data, length, entropy); if (ent->initialized < THRESHOLD_BITS) ent->initialized = THRESHOLD_BITS; UNLOCK(&ent->lock);}static voiddumpstats(isc_entropy_t *ent, FILE *out) { fprintf(out, isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY, ISC_MSG_ENTROPYSTATS, "Entropy pool %p: refcnt %u cursor %u," " rotate %u entropy %u pseudo %u nsources %u" " nextsource %p initialized %u initcount %u\n"), ent, ent->refcnt, ent->pool.cursor, ent->pool.rotate, ent->pool.entropy, ent->pool.pseudo, ent->nsources, ent->nextsource, ent->initialized, ent->initcount);}/* * This function ignores locking. Use at your own risk. */voidisc_entropy_stats(isc_entropy_t *ent, FILE *out) { REQUIRE(VALID_ENTROPY(ent)); LOCK(&ent->lock); dumpstats(ent, out); UNLOCK(&ent->lock);}voidisc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) { REQUIRE(VALID_ENTROPY(ent)); REQUIRE(entp != NULL && *entp == NULL); LOCK(&ent->lock); ent->refcnt++; *entp = ent; UNLOCK(&ent->lock);}voidisc_entropy_detach(isc_entropy_t **entp) { isc_entropy_t *ent; isc_boolean_t killit; REQUIRE(entp != NULL && VALID_ENTROPY(*entp)); ent = *entp; *entp = NULL; LOCK(&ent->lock); REQUIRE(ent->refcnt > 0); ent->refcnt--; killit = destroy_check(ent); UNLOCK(&ent->lock); if (killit) destroy(&ent);}static isc_result_tkbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { /* * The intent of "first" is to provide a warning message only once * during the run of a program that might try to gather keyboard * entropy multiple times. */ static isc_boolean_t first = ISC_TRUE; UNUSED(arg); if (! blocking) return (ISC_R_NOENTROPY); if (first) { if (source->warn_keyboard) fprintf(stderr, "You must use the keyboard to create " "entropy, since your system is lacking\n" "/dev/random (or equivalent)\n\n"); first = ISC_FALSE; } fprintf(stderr, "start typing:\n"); return (isc_keyboard_open(&source->kbd));}static voidkbdstop(isc_entropysource_t *source, void *arg) { UNUSED(arg); if (! isc_keyboard_canceled(&source->kbd)) fprintf(stderr, "stop typing.\r\n"); (void)isc_keyboard_close(&source->kbd, 3);}static isc_result_tkbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) { isc_result_t result; isc_time_t t; isc_uint32_t sample; isc_uint32_t extra; unsigned char c; UNUSED(arg); if (!blocking) return (ISC_R_NOTBLOCKING); result = isc_keyboard_getchar(&source->kbd, &c); if (result != ISC_R_SUCCESS) return (result); TIME_NOW(&t); sample = isc_time_nanoseconds(&t); extra = c; result = isc_entropy_addcallbacksample(source, sample, extra); if (result != ISC_R_SUCCESS) { fprintf(stderr, "\r\n"); return (result); } fprintf(stderr, "."); fflush(stderr); return (result);}isc_result_tisc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source, const char *randomfile, int use_keyboard){ isc_result_t result; isc_result_t final_result = ISC_R_NOENTROPY; isc_boolean_t userfile = ISC_TRUE; REQUIRE(VALID_ENTROPY(ectx)); REQUIRE(source != NULL && *source == NULL); REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES || use_keyboard == ISC_ENTROPY_KEYBOARDNO || use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);#ifdef PATH_RANDOMDEV if (randomfile == NULL) { randomfile = PATH_RANDOMDEV; userfile = ISC_FALSE; }#endif if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) { result = isc_entropy_createfilesource(ectx, randomfile); if (result == ISC_R_SUCCESS && use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE) use_keyboard = ISC_ENTROPY_KEYBOARDNO; if (result != ISC_R_SUCCESS && userfile) return (result); final_result = result; } if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) { result = isc_entropy_createcallbacksource(ectx, kbdstart, kbdget, kbdstop, NULL, source); if (result == ISC_R_SUCCESS) (*source)->warn_keyboard = ISC_TF(use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE); if (final_result != ISC_R_SUCCESS) final_result = result; } /* * final_result is ISC_R_SUCCESS if at least one source of entropy * could be started, otherwise it is the error from the most recently * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO). */ return (final_result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -