2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: entropy.c,v 1.3.2.2.2.7 2004/03/08 09:04:48 marka Exp $ */
21 * This is the system independent part of the entropy module. It is
22 * compiled via inclusion from the relevant OS source file, ie,
23 * unix/entropy.c or win32/entropy.c.
30 #include <isc/buffer.h>
31 #include <isc/entropy.h>
32 #include <isc/keyboard.h>
34 #include <isc/magic.h>
37 #include <isc/mutex.h>
38 #include <isc/platform.h>
39 #include <isc/region.h>
41 #include <isc/string.h>
46 * Much of this code is modeled after the NetBSD /dev/random implementation,
47 * written by Michael Graff <explorer@netbsd.org>.
50 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
51 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
53 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
54 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
57 *** "constants." Do not change these unless you _really_ know what
62 * size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
64 #define RND_POOLWORDS 128
65 #define RND_POOLBYTES (RND_POOLWORDS * 4)
66 #define RND_POOLBITS (RND_POOLWORDS * 32)
69 * Number of bytes returned per hash. This must be true:
70 * threshold * 2 <= digest_size_in_bytes
72 #define RND_ENTROPY_THRESHOLD 10
73 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
76 * Size of the input event queue in samples.
78 #define RND_EVENTQSIZE 32
81 * The number of times we'll "reseed" for pseudorandom seeds. This is an
82 * extremely weak pseudorandom seed. If the caller is using lots of
83 * pseudorandom data and they cannot provide a stronger random source,
84 * there is little we can do other than hope they're smart enough to
85 * call _adddata() with something better than we can come up with.
87 #define RND_INITIALIZE 128
90 isc_uint32_t cursor; /* current add point in the pool */
91 isc_uint32_t entropy; /* current entropy estimate in bits */
92 isc_uint32_t pseudo; /* bits extracted in pseudorandom */
93 isc_uint32_t rotate; /* how many bits to rotate by */
94 isc_uint32_t pool[RND_POOLWORDS]; /* random pool data */
102 isc_uint32_t initialized;
103 isc_uint32_t initcount;
104 isc_entropypool_t pool;
105 unsigned int nsources;
106 isc_entropysource_t *nextsource;
107 ISC_LIST(isc_entropysource_t) sources;
111 isc_uint32_t last_time; /* last time recorded */
112 isc_uint32_t last_delta; /* last delta value */
113 isc_uint32_t last_delta2; /* last delta2 value */
114 isc_uint32_t nsamples; /* number of samples filled in */
115 isc_uint32_t *samples; /* the samples */
116 isc_uint32_t *extra; /* extra samples added in */
120 sample_queue_t samplequeue;
121 } isc_entropysamplesource_t;
124 isc_boolean_t start_called;
125 isc_entropystart_t startfunc;
126 isc_entropyget_t getfunc;
127 isc_entropystop_t stopfunc;
129 sample_queue_t samplequeue;
133 FILESOURCE_HANDLE_TYPE handle;
134 } isc_entropyfilesource_t;
136 struct isc_entropysource {
140 isc_uint32_t total; /* entropy from this source */
141 ISC_LINK(isc_entropysource_t) link;
144 isc_boolean_t warn_keyboard;
147 isc_entropysamplesource_t sample;
148 isc_entropyfilesource_t file;
149 isc_cbsource_t callback;
150 isc_entropyusocketsource_t usocket;
154 #define ENTROPY_SOURCETYPE_SAMPLE 1 /* Type is a sample source */
155 #define ENTROPY_SOURCETYPE_FILE 2 /* Type is a file source */
156 #define ENTROPY_SOURCETYPE_CALLBACK 3 /* Type is a callback source */
157 #define ENTROPY_SOURCETYPE_USOCKET 4 /* Type is a Unix socket source */
160 * The random pool "taps"
169 * Declarations for function provided by the system dependent sources that
173 fillpool(isc_entropy_t *, unsigned int, isc_boolean_t);
176 wait_for_sources(isc_entropy_t *);
179 destroyfilesource(isc_entropyfilesource_t *source);
182 destroyusocketsource(isc_entropyusocketsource_t *source);
186 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
187 REQUIRE(sq->samples != NULL);
188 REQUIRE(sq->extra != NULL);
190 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
191 isc_mem_put(ent->mctx, sq->extra, RND_EVENTQSIZE * 4);
197 samplesource_allocate(isc_entropy_t *ent, sample_queue_t *sq) {
198 sq->samples = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
199 if (sq->samples == NULL)
200 return (ISC_R_NOMEMORY);
202 sq->extra = isc_mem_get(ent->mctx, RND_EVENTQSIZE * 4);
203 if (sq->extra == NULL) {
204 isc_mem_put(ent->mctx, sq->samples, RND_EVENTQSIZE * 4);
206 return (ISC_R_NOMEMORY);
211 return (ISC_R_SUCCESS);
215 * Add in entropy, even when the value we're adding in could be
219 add_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
220 /* clamp input. Yes, this must be done. */
221 entropy = ISC_MIN(entropy, RND_POOLBITS);
222 /* Add in the entropy we already have. */
223 entropy += ent->pool.entropy;
225 ent->pool.entropy = ISC_MIN(entropy, RND_POOLBITS);
229 * Decrement the amount of entropy the pool has.
232 subtract_entropy(isc_entropy_t *ent, isc_uint32_t entropy) {
233 entropy = ISC_MIN(entropy, ent->pool.entropy);
234 ent->pool.entropy -= entropy;
238 * Add in entropy, even when the value we're adding in could be
242 add_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
243 /* clamp input. Yes, this must be done. */
244 pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
245 /* Add in the pseudo we already have. */
246 pseudo += ent->pool.pseudo;
248 ent->pool.pseudo = ISC_MIN(pseudo, RND_POOLBITS * 8);
252 * Decrement the amount of pseudo the pool has.
255 subtract_pseudo(isc_entropy_t *ent, isc_uint32_t pseudo) {
256 pseudo = ISC_MIN(pseudo, ent->pool.pseudo);
257 ent->pool.pseudo -= pseudo;
261 * Add one word to the pool, rotating the input as needed.
264 entropypool_add_word(isc_entropypool_t *rp, isc_uint32_t val) {
266 * Steal some values out of the pool, and xor them into the
267 * word we were given.
269 * Mix the new value into the pool using xor. This will
270 * prevent the actual values from being known to the caller
271 * since the previous values are assumed to be unknown as well.
273 val ^= rp->pool[(rp->cursor + TAP1) & (RND_POOLWORDS - 1)];
274 val ^= rp->pool[(rp->cursor + TAP2) & (RND_POOLWORDS - 1)];
275 val ^= rp->pool[(rp->cursor + TAP3) & (RND_POOLWORDS - 1)];
276 val ^= rp->pool[(rp->cursor + TAP4) & (RND_POOLWORDS - 1)];
277 val ^= rp->pool[(rp->cursor + TAP5) & (RND_POOLWORDS - 1)];
278 rp->pool[rp->cursor++] ^=
279 ((val << rp->rotate) | (val >> (32 - rp->rotate)));
282 * If we have looped around the pool, increment the rotate
283 * variable so the next value will get xored in rotated to
284 * a different position.
285 * Increment by a value that is relativly prime to the word size
286 * to try to spread the bits throughout the pool quickly when the
289 if (rp->cursor == RND_POOLWORDS) {
291 rp->rotate = (rp->rotate + 7) & 31;
296 * Add a buffer's worth of data to the pool.
298 * Requires that the lock is held on the entropy pool.
301 entropypool_adddata(isc_entropy_t *ent, void *p, unsigned int len,
302 isc_uint32_t entropy)
308 addr = (unsigned long)p;
311 if ((addr & 0x03U) != 0U) {
318 val = val << 8 | *buf++;
321 val = val << 8 | *buf++;
325 entropypool_add_word(&ent->pool, val);
328 for (; len > 3; len -= 4) {
329 val = *((isc_uint32_t *)buf);
331 entropypool_add_word(&ent->pool, val);
341 val = val << 8 | *buf++;
343 val = val << 8 | *buf++;
346 entropypool_add_word(&ent->pool, val);
349 add_entropy(ent, entropy);
350 subtract_pseudo(ent, entropy);
354 reseed(isc_entropy_t *ent) {
358 if (ent->initcount == 0) {
360 entropypool_adddata(ent, &pid, sizeof(pid), 0);
362 entropypool_adddata(ent, &pid, sizeof(pid), 0);
366 * After we've reseeded 100 times, only add new timing info every
367 * 50 requests. This will keep us from using lots and lots of
368 * CPU just to return bad pseudorandom data anyway.
370 if (ent->initcount > 100)
371 if ((ent->initcount % 50) != 0)
375 entropypool_adddata(ent, &t, sizeof(t), 0);
379 static inline unsigned int
380 estimate_entropy(sample_queue_t *sq, isc_uint32_t t) {
386 * If the time counter has overflowed, calculate the real difference.
387 * If it has not, it is simpler.
389 if (t < sq->last_time)
390 delta = UINT_MAX - sq->last_time + t;
392 delta = sq->last_time - t;
398 * Calculate the second and third order differentials
400 delta2 = sq->last_delta - delta;
404 delta3 = sq->last_delta2 - delta2;
409 sq->last_delta = delta;
410 sq->last_delta2 = delta2;
413 * If any delta is 0, we got no entropy. If all are non-zero, we
414 * might have something.
416 if (delta == 0 || delta2 == 0 || delta3 == 0)
420 * We could find the smallest delta and claim we got log2(delta)
421 * bits, but for now return that we found 1 bit.
427 crunchsamples(isc_entropy_t *ent, sample_queue_t *sq) {
431 if (sq->nsamples < 6)
435 sq->last_time = sq->samples[0];
440 * Prime the values by adding in the first 4 samples in. This
441 * should completely initialize the delta calculations.
443 for (ns = 0; ns < 4; ns++)
444 (void)estimate_entropy(sq, sq->samples[ns]);
446 for (ns = 4; ns < sq->nsamples; ns++)
447 added += estimate_entropy(sq, sq->samples[ns]);
449 entropypool_adddata(ent, sq->samples, sq->nsamples * 4, added);
450 entropypool_adddata(ent, sq->extra, sq->nsamples * 4, 0);
453 * Move the last 4 samples into the first 4 positions, and start
454 * adding new samples from that point.
456 for (ns = 0; ns < 4; ns++) {
457 sq->samples[ns] = sq->samples[sq->nsamples - 4 + ns];
458 sq->extra[ns] = sq->extra[sq->nsamples - 4 + ns];
467 get_from_callback(isc_entropysource_t *source, unsigned int desired,
468 isc_boolean_t blocking)
470 isc_entropy_t *ent = source->ent;
471 isc_cbsource_t *cbs = &source->sources.callback;
482 if (!cbs->start_called && cbs->startfunc != NULL) {
483 result = cbs->startfunc(source, cbs->arg, blocking);
484 if (result != ISC_R_SUCCESS)
486 cbs->start_called = ISC_TRUE;
490 result = ISC_R_SUCCESS;
491 while (desired > 0 && result == ISC_R_SUCCESS) {
492 result = cbs->getfunc(source, cbs->arg, blocking);
493 if (result == ISC_R_QUEUEFULL) {
494 got = crunchsamples(ent, &cbs->samplequeue);
496 desired -= ISC_MIN(got, desired);
497 result = ISC_R_SUCCESS;
498 } else if (result != ISC_R_SUCCESS &&
499 result != ISC_R_NOTBLOCKING)
500 source->bad = ISC_TRUE;
508 * Extract some number of bytes from the random pool, decreasing the
509 * estimate of randomness as each byte is extracted.
511 * Do this by stiring the pool and returning a part of hash as randomness.
512 * Note that no secrets are given away here since parts of the hash are
513 * xored together before returned.
515 * Honor the request from the caller to only return good data, any data,
519 isc_entropy_getdata(isc_entropy_t *ent, void *data, unsigned int length,
520 unsigned int *returned, unsigned int flags)
524 unsigned char digest[ISC_SHA1_DIGESTLENGTH];
525 isc_uint32_t remain, deltae, count, total;
527 isc_boolean_t goodonly, partial, blocking;
529 REQUIRE(VALID_ENTROPY(ent));
530 REQUIRE(data != NULL);
533 goodonly = ISC_TF((flags & ISC_ENTROPY_GOODONLY) != 0);
534 partial = ISC_TF((flags & ISC_ENTROPY_PARTIAL) != 0);
535 blocking = ISC_TF((flags & ISC_ENTROPY_BLOCKING) != 0);
537 REQUIRE(!partial || returned != NULL);
544 while (remain != 0) {
545 count = ISC_MIN(remain, RND_ENTROPY_THRESHOLD);
548 * If we are extracting good data only, make certain we
549 * have enough data in our pool for this pass. If we don't,
550 * get some, and fail if we can't, and partial returns
554 unsigned int fillcount;
556 fillcount = ISC_MAX(remain * 8, count * 8);
559 * If, however, we have at least THRESHOLD_BITS
560 * of entropy in the pool, don't block here. It is
561 * better to drain the pool once in a while and
562 * then refill it than it is to constantly keep the
565 if (ent->pool.entropy >= THRESHOLD_BITS)
566 fillpool(ent, fillcount, ISC_FALSE);
568 fillpool(ent, fillcount, blocking);
571 * Verify that we got enough entropy to do one
572 * extraction. If we didn't, bail.
574 if (ent->pool.entropy < THRESHOLD_BITS) {
582 * If we've extracted half our pool size in bits
583 * since the last refresh, try to refresh here.
585 if (ent->initialized < THRESHOLD_BITS)
586 fillpool(ent, THRESHOLD_BITS, blocking);
588 fillpool(ent, 0, ISC_FALSE);
591 * If we've not initialized with enough good random
592 * data, seed with our crappy code.
594 if (ent->initialized < THRESHOLD_BITS)
598 isc_sha1_init(&hash);
599 isc_sha1_update(&hash, (void *)(ent->pool.pool),
601 isc_sha1_final(&hash, digest);
604 * Stir the extracted data (all of it) back into the pool.
606 entropypool_adddata(ent, digest, ISC_SHA1_DIGESTLENGTH, 0);
608 for (i = 0; i < count; i++)
609 buf[i] = digest[i] ^ digest[i + RND_ENTROPY_THRESHOLD];
615 deltae = ISC_MIN(deltae, ent->pool.entropy);
617 subtract_entropy(ent, deltae);
618 add_pseudo(ent, count * 8);
622 memset(digest, 0, sizeof(digest));
624 if (returned != NULL)
625 *returned = (length - remain);
629 return (ISC_R_SUCCESS);
632 /* put the entropy we almost extracted back */
633 add_entropy(ent, total);
634 memset(data, 0, length);
635 memset(digest, 0, sizeof(digest));
636 if (returned != NULL)
641 return (ISC_R_NOENTROPY);
645 isc_entropypool_init(isc_entropypool_t *pool) {
646 pool->cursor = RND_POOLWORDS - 1;
650 memset(pool->pool, 0, RND_POOLBYTES);
654 isc_entropypool_invalidate(isc_entropypool_t *pool) {
659 memset(pool->pool, 0, RND_POOLBYTES);
663 isc_entropy_create(isc_mem_t *mctx, isc_entropy_t **entp) {
667 REQUIRE(mctx != NULL);
668 REQUIRE(entp != NULL && *entp == NULL);
670 ent = isc_mem_get(mctx, sizeof(isc_entropy_t));
672 return (ISC_R_NOMEMORY);
677 if (isc_mutex_init(&ent->lock) != ISC_R_SUCCESS) {
678 ret = ISC_R_UNEXPECTED;
683 * From here down, no failures will/can occur.
685 ISC_LIST_INIT(ent->sources);
686 ent->nextsource = NULL;
689 isc_mem_attach(mctx, &ent->mctx);
691 ent->initialized = 0;
693 ent->magic = ENTROPY_MAGIC;
695 isc_entropypool_init(&ent->pool);
698 return (ISC_R_SUCCESS);
701 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
707 * Requires "ent" be locked.
710 destroysource(isc_entropysource_t **sourcep) {
711 isc_entropysource_t *source;
719 ISC_LIST_UNLINK(ent->sources, source, link);
720 ent->nextsource = NULL;
721 REQUIRE(ent->nsources > 0);
724 switch (source->type) {
725 case ENTROPY_SOURCETYPE_FILE:
727 destroyfilesource(&source->sources.file);
729 case ENTROPY_SOURCETYPE_USOCKET:
731 destroyusocketsource(&source->sources.usocket);
733 case ENTROPY_SOURCETYPE_SAMPLE:
734 samplequeue_release(ent, &source->sources.sample.samplequeue);
736 case ENTROPY_SOURCETYPE_CALLBACK:
737 cbs = &source->sources.callback;
738 if (cbs->start_called && cbs->stopfunc != NULL) {
739 cbs->stopfunc(source, cbs->arg);
740 cbs->start_called = ISC_FALSE;
742 samplequeue_release(ent, &cbs->samplequeue);
746 memset(source, 0, sizeof(isc_entropysource_t));
748 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
751 static inline isc_boolean_t
752 destroy_check(isc_entropy_t *ent) {
753 isc_entropysource_t *source;
758 source = ISC_LIST_HEAD(ent->sources);
759 while (source != NULL) {
760 switch (source->type) {
761 case ENTROPY_SOURCETYPE_FILE:
762 case ENTROPY_SOURCETYPE_USOCKET:
767 source = ISC_LIST_NEXT(source, link);
774 destroy(isc_entropy_t **entp) {
776 isc_entropysource_t *source;
779 REQUIRE(entp != NULL && *entp != NULL);
785 REQUIRE(ent->refcnt == 0);
788 * Here, detach non-sample sources.
790 source = ISC_LIST_HEAD(ent->sources);
791 while (source != NULL) {
792 switch(source->type) {
793 case ENTROPY_SOURCETYPE_FILE:
794 case ENTROPY_SOURCETYPE_USOCKET:
795 destroysource(&source);
798 source = ISC_LIST_HEAD(ent->sources);
802 * If there are other types of sources, we've found a bug.
804 REQUIRE(ISC_LIST_EMPTY(ent->sources));
808 isc_entropypool_invalidate(&ent->pool);
812 DESTROYLOCK(&ent->lock);
814 memset(ent, 0, sizeof(isc_entropy_t));
815 isc_mem_put(mctx, ent, sizeof(isc_entropy_t));
816 isc_mem_detach(&mctx);
820 isc_entropy_destroysource(isc_entropysource_t **sourcep) {
821 isc_entropysource_t *source;
823 isc_boolean_t killit;
825 REQUIRE(sourcep != NULL);
826 REQUIRE(VALID_SOURCE(*sourcep));
832 REQUIRE(VALID_ENTROPY(ent));
836 destroysource(&source);
838 killit = destroy_check(ent);
847 isc_entropy_createcallbacksource(isc_entropy_t *ent,
848 isc_entropystart_t start,
849 isc_entropyget_t get,
850 isc_entropystop_t stop,
852 isc_entropysource_t **sourcep)
855 isc_entropysource_t *source;
858 REQUIRE(VALID_ENTROPY(ent));
859 REQUIRE(get != NULL);
860 REQUIRE(sourcep != NULL && *sourcep == NULL);
864 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
865 if (source == NULL) {
866 ret = ISC_R_NOMEMORY;
869 source->bad = ISC_FALSE;
871 cbs = &source->sources.callback;
873 ret = samplesource_allocate(ent, &cbs->samplequeue);
874 if (ret != ISC_R_SUCCESS)
877 cbs->start_called = ISC_FALSE;
878 cbs->startfunc = start;
880 cbs->stopfunc = stop;
884 * From here down, no failures can occur.
886 source->magic = SOURCE_MAGIC;
887 source->type = ENTROPY_SOURCETYPE_CALLBACK;
890 memset(source->name, 0, sizeof(source->name));
891 ISC_LINK_INIT(source, link);
894 * Hook it into the entropy system.
896 ISC_LIST_APPEND(ent->sources, source, link);
902 return (ISC_R_SUCCESS);
906 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
914 isc_entropy_stopcallbacksources(isc_entropy_t *ent) {
915 isc_entropysource_t *source;
918 REQUIRE(VALID_ENTROPY(ent));
922 source = ISC_LIST_HEAD(ent->sources);
923 while (source != NULL) {
924 if (source->type == ENTROPY_SOURCETYPE_CALLBACK) {
925 cbs = &source->sources.callback;
926 if (cbs->start_called && cbs->stopfunc != NULL) {
927 cbs->stopfunc(source, cbs->arg);
928 cbs->start_called = ISC_FALSE;
932 source = ISC_LIST_NEXT(source, link);
939 isc_entropy_createsamplesource(isc_entropy_t *ent,
940 isc_entropysource_t **sourcep)
943 isc_entropysource_t *source;
946 REQUIRE(VALID_ENTROPY(ent));
947 REQUIRE(sourcep != NULL && *sourcep == NULL);
951 source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
952 if (source == NULL) {
953 ret = ISC_R_NOMEMORY;
957 sq = &source->sources.sample.samplequeue;
958 ret = samplesource_allocate(ent, sq);
959 if (ret != ISC_R_SUCCESS)
963 * From here down, no failures can occur.
965 source->magic = SOURCE_MAGIC;
966 source->type = ENTROPY_SOURCETYPE_SAMPLE;
969 memset(source->name, 0, sizeof(source->name));
970 ISC_LINK_INIT(source, link);
973 * Hook it into the entropy system.
975 ISC_LIST_APPEND(ent->sources, source, link);
981 return (ISC_R_SUCCESS);
985 isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));
993 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
994 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
995 * queue was full when this function was called.
998 addsample(sample_queue_t *sq, isc_uint32_t sample, isc_uint32_t extra) {
999 if (sq->nsamples >= RND_EVENTQSIZE)
1000 return (ISC_R_NOMORE);
1002 sq->samples[sq->nsamples] = sample;
1003 sq->extra[sq->nsamples] = extra;
1006 if (sq->nsamples >= RND_EVENTQSIZE)
1007 return (ISC_R_QUEUEFULL);
1009 return (ISC_R_SUCCESS);
1013 isc_entropy_addsample(isc_entropysource_t *source, isc_uint32_t sample,
1018 unsigned int entropy;
1019 isc_result_t result;
1021 REQUIRE(VALID_SOURCE(source));
1027 sq = &source->sources.sample.samplequeue;
1028 result = addsample(sq, sample, extra);
1029 if (result == ISC_R_QUEUEFULL) {
1030 entropy = crunchsamples(ent, sq);
1031 add_entropy(ent, entropy);
1040 isc_entropy_addcallbacksample(isc_entropysource_t *source, isc_uint32_t sample,
1044 isc_result_t result;
1046 REQUIRE(VALID_SOURCE(source));
1047 REQUIRE(source->type == ENTROPY_SOURCETYPE_CALLBACK);
1049 sq = &source->sources.callback.samplequeue;
1050 result = addsample(sq, sample, extra);
1056 isc_entropy_putdata(isc_entropy_t *ent, void *data, unsigned int length,
1057 isc_uint32_t entropy)
1059 REQUIRE(VALID_ENTROPY(ent));
1063 entropypool_adddata(ent, data, length, entropy);
1065 if (ent->initialized < THRESHOLD_BITS)
1066 ent->initialized = THRESHOLD_BITS;
1072 dumpstats(isc_entropy_t *ent, FILE *out) {
1074 isc_msgcat_get(isc_msgcat, ISC_MSGSET_ENTROPY,
1075 ISC_MSG_ENTROPYSTATS,
1076 "Entropy pool %p: refcnt %u cursor %u,"
1077 " rotate %u entropy %u pseudo %u nsources %u"
1078 " nextsource %p initialized %u initcount %u\n"),
1080 ent->pool.cursor, ent->pool.rotate,
1081 ent->pool.entropy, ent->pool.pseudo,
1082 ent->nsources, ent->nextsource, ent->initialized,
1087 * This function ignores locking. Use at your own risk.
1090 isc_entropy_stats(isc_entropy_t *ent, FILE *out) {
1091 REQUIRE(VALID_ENTROPY(ent));
1094 dumpstats(ent, out);
1099 isc_entropy_attach(isc_entropy_t *ent, isc_entropy_t **entp) {
1100 REQUIRE(VALID_ENTROPY(ent));
1101 REQUIRE(entp != NULL && *entp == NULL);
1112 isc_entropy_detach(isc_entropy_t **entp) {
1114 isc_boolean_t killit;
1116 REQUIRE(entp != NULL && VALID_ENTROPY(*entp));
1122 REQUIRE(ent->refcnt > 0);
1125 killit = destroy_check(ent);
1134 kbdstart(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1136 * The intent of "first" is to provide a warning message only once
1137 * during the run of a program that might try to gather keyboard
1138 * entropy multiple times.
1140 static isc_boolean_t first = ISC_TRUE;
1145 return (ISC_R_NOENTROPY);
1148 if (source->warn_keyboard)
1149 fprintf(stderr, "You must use the keyboard to create "
1150 "entropy, since your system is lacking\n"
1151 "/dev/random (or equivalent)\n\n");
1154 fprintf(stderr, "start typing:\n");
1156 return (isc_keyboard_open(&source->kbd));
1160 kbdstop(isc_entropysource_t *source, void *arg) {
1164 if (! isc_keyboard_canceled(&source->kbd))
1165 fprintf(stderr, "stop typing.\r\n");
1167 (void)isc_keyboard_close(&source->kbd, 3);
1171 kbdget(isc_entropysource_t *source, void *arg, isc_boolean_t blocking) {
1172 isc_result_t result;
1174 isc_uint32_t sample;
1181 return (ISC_R_NOTBLOCKING);
1183 result = isc_keyboard_getchar(&source->kbd, &c);
1184 if (result != ISC_R_SUCCESS)
1189 sample = isc_time_nanoseconds(&t);
1192 result = isc_entropy_addcallbacksample(source, sample, extra);
1193 if (result != ISC_R_SUCCESS) {
1194 fprintf(stderr, "\r\n");
1198 fprintf(stderr, ".");
1205 isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source,
1206 const char *randomfile, int use_keyboard)
1208 isc_result_t result;
1209 isc_result_t final_result = ISC_R_NOENTROPY;
1210 isc_boolean_t userfile = ISC_TRUE;
1212 REQUIRE(VALID_ENTROPY(ectx));
1213 REQUIRE(source != NULL && *source == NULL);
1214 REQUIRE(use_keyboard == ISC_ENTROPY_KEYBOARDYES ||
1215 use_keyboard == ISC_ENTROPY_KEYBOARDNO ||
1216 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE);
1218 #ifdef PATH_RANDOMDEV
1219 if (randomfile == NULL) {
1220 randomfile = PATH_RANDOMDEV;
1221 userfile = ISC_FALSE;
1225 if (randomfile != NULL && use_keyboard != ISC_ENTROPY_KEYBOARDYES) {
1226 result = isc_entropy_createfilesource(ectx, randomfile);
1227 if (result == ISC_R_SUCCESS &&
1228 use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE)
1229 use_keyboard = ISC_ENTROPY_KEYBOARDNO;
1230 if (result != ISC_R_SUCCESS && userfile)
1233 final_result = result;
1236 if (use_keyboard != ISC_ENTROPY_KEYBOARDNO) {
1237 result = isc_entropy_createcallbacksource(ectx, kbdstart,
1240 if (result == ISC_R_SUCCESS)
1241 (*source)->warn_keyboard =
1242 ISC_TF(use_keyboard ==
1243 ISC_ENTROPY_KEYBOARDMAYBE);
1245 if (final_result != ISC_R_SUCCESS)
1246 final_result = result;
1250 * final_result is ISC_R_SUCCESS if at least one source of entropy
1251 * could be started, otherwise it is the error from the most recently
1252 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1253 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1255 return (final_result);