4 * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2000-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: entropy.c,v 1.20 2009/01/18 23:48:14 tbox Exp */
24 * This is the system independent part of the entropy module. It is
25 * compiled via inclusion from the relevant OS source file, ie,
26 * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
28 * \author Much of this code is modeled after the NetBSD /dev/random implementation,
29 * written by Michael Graff <explorer@netbsd.org>.
36 #include <isc/buffer.h>
37 #include <isc/entropy.h>
38 #include <isc/keyboard.h>
40 #include <isc/magic.h>
43 #include <isc/mutex.h>
44 #include <isc/platform.h>
45 #include <isc/region.h>
47 #include <isc/string.h>
52 #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e')
53 #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's')
55 #define VALID_ENTROPY(e) ISC_MAGIC_VALID(e, ENTROPY_MAGIC)
56 #define VALID_SOURCE(s) ISC_MAGIC_VALID(s, SOURCE_MAGIC)
59 *** "constants." Do not change these unless you _really_ know what
64 * Size of entropy pool in 32-bit words. This _MUST_ be a power of 2.
66 #define RND_POOLWORDS 128
68 #define RND_POOLBYTES (RND_POOLWORDS * 4)
70 #define RND_POOLBITS (RND_POOLWORDS * 32)
73 * Number of bytes returned per hash. This must be true:
74 * threshold * 2 <= digest_size_in_bytes
76 #define RND_ENTROPY_THRESHOLD 10
77 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
80 * Size of the input event queue in samples.
82 #define RND_EVENTQSIZE 32
85 * The number of times we'll "reseed" for pseudorandom seeds. This is an
86 * extremely weak pseudorandom seed. If the caller is using lots of
87 * pseudorandom data and they cannot provide a stronger random source,
88 * there is little we can do other than hope they're smart enough to
89 * call _adddata() with something better than we can come up with.
91 #define RND_INITIALIZE 128
95 isc_uint32_t cursor
; /*%< current add point in the pool */
96 isc_uint32_t entropy
; /*%< current entropy estimate in bits */
97 isc_uint32_t pseudo
; /*%< bits extracted in pseudorandom */
98 isc_uint32_t rotate
; /*%< how many bits to rotate by */
99 isc_uint32_t pool
[RND_POOLWORDS
]; /*%< random pool data */
107 isc_uint32_t initialized
;
108 isc_uint32_t initcount
;
109 isc_entropypool_t pool
;
110 unsigned int nsources
;
111 isc_entropysource_t
*nextsource
;
112 ISC_LIST(isc_entropysource_t
) sources
;
117 isc_uint32_t last_time
; /*%< last time recorded */
118 isc_uint32_t last_delta
; /*%< last delta value */
119 isc_uint32_t last_delta2
; /*%< last delta2 value */
120 isc_uint32_t nsamples
; /*%< number of samples filled in */
121 isc_uint32_t
*samples
; /*%< the samples */
122 isc_uint32_t
*extra
; /*%< extra samples added in */
126 sample_queue_t samplequeue
;
127 } isc_entropysamplesource_t
;
130 isc_boolean_t start_called
;
131 isc_entropystart_t startfunc
;
132 isc_entropyget_t getfunc
;
133 isc_entropystop_t stopfunc
;
135 sample_queue_t samplequeue
;
139 FILESOURCE_HANDLE_TYPE handle
;
140 } isc_entropyfilesource_t
;
142 struct isc_entropysource
{
146 isc_uint32_t total
; /*%< entropy from this source */
147 ISC_LINK(isc_entropysource_t
) link
;
150 isc_boolean_t warn_keyboard
;
153 isc_entropysamplesource_t sample
;
154 isc_entropyfilesource_t file
;
155 isc_cbsource_t callback
;
156 isc_entropyusocketsource_t usocket
;
160 #define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
161 #define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
162 #define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
163 #define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
167 * The random pool "taps"
178 * Declarations for function provided by the system dependent sources that
182 fillpool(isc_entropy_t
*, unsigned int, isc_boolean_t
);
185 wait_for_sources(isc_entropy_t
*);
188 destroyfilesource(isc_entropyfilesource_t
*source
);
191 destroyusocketsource(isc_entropyusocketsource_t
*source
);
196 samplequeue_release(isc_entropy_t
*ent
, sample_queue_t
*sq
) {
197 REQUIRE(sq
->samples
!= NULL
);
198 REQUIRE(sq
->extra
!= NULL
);
200 isc_mem_put(ent
->mctx
, sq
->samples
, RND_EVENTQSIZE
* 4);
201 isc_mem_put(ent
->mctx
, sq
->extra
, RND_EVENTQSIZE
* 4);
207 samplesource_allocate(isc_entropy_t
*ent
, sample_queue_t
*sq
) {
208 sq
->samples
= isc_mem_get(ent
->mctx
, RND_EVENTQSIZE
* 4);
209 if (sq
->samples
== NULL
)
210 return (ISC_R_NOMEMORY
);
212 sq
->extra
= isc_mem_get(ent
->mctx
, RND_EVENTQSIZE
* 4);
213 if (sq
->extra
== NULL
) {
214 isc_mem_put(ent
->mctx
, sq
->samples
, RND_EVENTQSIZE
* 4);
216 return (ISC_R_NOMEMORY
);
221 return (ISC_R_SUCCESS
);
225 * Add in entropy, even when the value we're adding in could be
229 add_entropy(isc_entropy_t
*ent
, isc_uint32_t entropy
) {
230 /* clamp input. Yes, this must be done. */
231 entropy
= ISC_MIN(entropy
, RND_POOLBITS
);
232 /* Add in the entropy we already have. */
233 entropy
+= ent
->pool
.entropy
;
235 ent
->pool
.entropy
= ISC_MIN(entropy
, RND_POOLBITS
);
239 * Decrement the amount of entropy the pool has.
242 subtract_entropy(isc_entropy_t
*ent
, isc_uint32_t entropy
) {
243 entropy
= ISC_MIN(entropy
, ent
->pool
.entropy
);
244 ent
->pool
.entropy
-= entropy
;
248 * Add in entropy, even when the value we're adding in could be
252 add_pseudo(isc_entropy_t
*ent
, isc_uint32_t pseudo
) {
253 /* clamp input. Yes, this must be done. */
254 pseudo
= ISC_MIN(pseudo
, RND_POOLBITS
* 8);
255 /* Add in the pseudo we already have. */
256 pseudo
+= ent
->pool
.pseudo
;
258 ent
->pool
.pseudo
= ISC_MIN(pseudo
, RND_POOLBITS
* 8);
262 * Decrement the amount of pseudo the pool has.
265 subtract_pseudo(isc_entropy_t
*ent
, isc_uint32_t pseudo
) {
266 pseudo
= ISC_MIN(pseudo
, ent
->pool
.pseudo
);
267 ent
->pool
.pseudo
-= pseudo
;
271 * Add one word to the pool, rotating the input as needed.
274 entropypool_add_word(isc_entropypool_t
*rp
, isc_uint32_t val
) {
276 * Steal some values out of the pool, and xor them into the
277 * word we were given.
279 * Mix the new value into the pool using xor. This will
280 * prevent the actual values from being known to the caller
281 * since the previous values are assumed to be unknown as well.
283 val
^= rp
->pool
[(rp
->cursor
+ TAP1
) & (RND_POOLWORDS
- 1)];
284 val
^= rp
->pool
[(rp
->cursor
+ TAP2
) & (RND_POOLWORDS
- 1)];
285 val
^= rp
->pool
[(rp
->cursor
+ TAP3
) & (RND_POOLWORDS
- 1)];
286 val
^= rp
->pool
[(rp
->cursor
+ TAP4
) & (RND_POOLWORDS
- 1)];
287 val
^= rp
->pool
[(rp
->cursor
+ TAP5
) & (RND_POOLWORDS
- 1)];
288 rp
->pool
[rp
->cursor
++] ^=
289 ((val
<< rp
->rotate
) | (val
>> (32 - rp
->rotate
)));
292 * If we have looped around the pool, increment the rotate
293 * variable so the next value will get xored in rotated to
294 * a different position.
295 * Increment by a value that is relatively prime to the word size
296 * to try to spread the bits throughout the pool quickly when the
299 if (rp
->cursor
== RND_POOLWORDS
) {
301 rp
->rotate
= (rp
->rotate
+ 7) & 31;
306 * Add a buffer's worth of data to the pool.
308 * Requires that the lock is held on the entropy pool.
311 entropypool_adddata(isc_entropy_t
*ent
, void *p
, unsigned int len
,
312 isc_uint32_t entropy
)
318 addr
= (unsigned long)p
;
321 if ((addr
& 0x03U
) != 0U) {
328 val
= val
<< 8 | *buf
++;
331 val
= val
<< 8 | *buf
++;
335 entropypool_add_word(&ent
->pool
, val
);
338 for (; len
> 3; len
-= 4) {
339 val
= *((isc_uint32_t
*)buf
);
341 entropypool_add_word(&ent
->pool
, val
);
351 val
= val
<< 8 | *buf
++;
353 val
= val
<< 8 | *buf
++;
356 entropypool_add_word(&ent
->pool
, val
);
359 add_entropy(ent
, entropy
);
360 subtract_pseudo(ent
, entropy
);
364 reseed(isc_entropy_t
*ent
) {
368 if (ent
->initcount
== 0) {
370 entropypool_adddata(ent
, &pid
, sizeof(pid
), 0);
372 entropypool_adddata(ent
, &pid
, sizeof(pid
), 0);
376 * After we've reseeded 100 times, only add new timing info every
377 * 50 requests. This will keep us from using lots and lots of
378 * CPU just to return bad pseudorandom data anyway.
380 if (ent
->initcount
> 100)
381 if ((ent
->initcount
% 50) != 0)
385 entropypool_adddata(ent
, &t
, sizeof(t
), 0);
389 static inline unsigned int
390 estimate_entropy(sample_queue_t
*sq
, isc_uint32_t t
) {
396 * If the time counter has overflowed, calculate the real difference.
397 * If it has not, it is simpler.
399 if (t
< sq
->last_time
)
400 delta
= UINT_MAX
- sq
->last_time
+ t
;
402 delta
= sq
->last_time
- t
;
408 * Calculate the second and third order differentials
410 delta2
= sq
->last_delta
- delta
;
414 delta3
= sq
->last_delta2
- delta2
;
419 sq
->last_delta
= delta
;
420 sq
->last_delta2
= delta2
;
423 * If any delta is 0, we got no entropy. If all are non-zero, we
424 * might have something.
426 if (delta
== 0 || delta2
== 0 || delta3
== 0)
430 * We could find the smallest delta and claim we got log2(delta)
431 * bits, but for now return that we found 1 bit.
437 crunchsamples(isc_entropy_t
*ent
, sample_queue_t
*sq
) {
441 if (sq
->nsamples
< 6)
445 sq
->last_time
= sq
->samples
[0];
450 * Prime the values by adding in the first 4 samples in. This
451 * should completely initialize the delta calculations.
453 for (ns
= 0; ns
< 4; ns
++)
454 (void)estimate_entropy(sq
, sq
->samples
[ns
]);
456 for (ns
= 4; ns
< sq
->nsamples
; ns
++)
457 added
+= estimate_entropy(sq
, sq
->samples
[ns
]);
459 entropypool_adddata(ent
, sq
->samples
, sq
->nsamples
* 4, added
);
460 entropypool_adddata(ent
, sq
->extra
, sq
->nsamples
* 4, 0);
463 * Move the last 4 samples into the first 4 positions, and start
464 * adding new samples from that point.
466 for (ns
= 0; ns
< 4; ns
++) {
467 sq
->samples
[ns
] = sq
->samples
[sq
->nsamples
- 4 + ns
];
468 sq
->extra
[ns
] = sq
->extra
[sq
->nsamples
- 4 + ns
];
477 get_from_callback(isc_entropysource_t
*source
, unsigned int desired
,
478 isc_boolean_t blocking
)
480 isc_entropy_t
*ent
= source
->ent
;
481 isc_cbsource_t
*cbs
= &source
->sources
.callback
;
492 if (!cbs
->start_called
&& cbs
->startfunc
!= NULL
) {
493 result
= cbs
->startfunc(source
, cbs
->arg
, blocking
);
494 if (result
!= ISC_R_SUCCESS
)
496 cbs
->start_called
= ISC_TRUE
;
500 result
= ISC_R_SUCCESS
;
501 while (desired
> 0 && result
== ISC_R_SUCCESS
) {
502 result
= cbs
->getfunc(source
, cbs
->arg
, blocking
);
503 if (result
== ISC_R_QUEUEFULL
) {
504 got
= crunchsamples(ent
, &cbs
->samplequeue
);
506 desired
-= ISC_MIN(got
, desired
);
507 result
= ISC_R_SUCCESS
;
508 } else if (result
!= ISC_R_SUCCESS
&&
509 result
!= ISC_R_NOTBLOCKING
)
510 source
->bad
= ISC_TRUE
;
518 * Extract some number of bytes from the random pool, decreasing the
519 * estimate of randomness as each byte is extracted.
521 * Do this by stiring the pool and returning a part of hash as randomness.
522 * Note that no secrets are given away here since parts of the hash are
523 * xored together before returned.
525 * Honor the request from the caller to only return good data, any data,
529 isc_entropy_getdata(isc_entropy_t
*ent
, void *data
, unsigned int length
,
530 unsigned int *returned
, unsigned int flags
)
534 unsigned char digest
[ISC_SHA1_DIGESTLENGTH
];
535 isc_uint32_t remain
, deltae
, count
, total
;
537 isc_boolean_t goodonly
, partial
, blocking
;
539 REQUIRE(VALID_ENTROPY(ent
));
540 REQUIRE(data
!= NULL
);
543 goodonly
= ISC_TF((flags
& ISC_ENTROPY_GOODONLY
) != 0);
544 partial
= ISC_TF((flags
& ISC_ENTROPY_PARTIAL
) != 0);
545 blocking
= ISC_TF((flags
& ISC_ENTROPY_BLOCKING
) != 0);
547 REQUIRE(!partial
|| returned
!= NULL
);
554 while (remain
!= 0) {
555 count
= ISC_MIN(remain
, RND_ENTROPY_THRESHOLD
);
558 * If we are extracting good data only, make certain we
559 * have enough data in our pool for this pass. If we don't,
560 * get some, and fail if we can't, and partial returns
564 unsigned int fillcount
;
566 fillcount
= ISC_MAX(remain
* 8, count
* 8);
569 * If, however, we have at least THRESHOLD_BITS
570 * of entropy in the pool, don't block here. It is
571 * better to drain the pool once in a while and
572 * then refill it than it is to constantly keep the
575 if (ent
->pool
.entropy
>= THRESHOLD_BITS
)
576 fillpool(ent
, fillcount
, ISC_FALSE
);
578 fillpool(ent
, fillcount
, blocking
);
581 * Verify that we got enough entropy to do one
582 * extraction. If we didn't, bail.
584 if (ent
->pool
.entropy
< THRESHOLD_BITS
) {
592 * If we've extracted half our pool size in bits
593 * since the last refresh, try to refresh here.
595 if (ent
->initialized
< THRESHOLD_BITS
)
596 fillpool(ent
, THRESHOLD_BITS
, blocking
);
598 fillpool(ent
, 0, ISC_FALSE
);
601 * If we've not initialized with enough good random
602 * data, seed with our crappy code.
604 if (ent
->initialized
< THRESHOLD_BITS
)
608 isc_sha1_init(&hash
);
609 isc_sha1_update(&hash
, (void *)(ent
->pool
.pool
),
611 isc_sha1_final(&hash
, digest
);
614 * Stir the extracted data (all of it) back into the pool.
616 entropypool_adddata(ent
, digest
, ISC_SHA1_DIGESTLENGTH
, 0);
618 for (i
= 0; i
< count
; i
++)
619 buf
[i
] = digest
[i
] ^ digest
[i
+ RND_ENTROPY_THRESHOLD
];
625 deltae
= ISC_MIN(deltae
, ent
->pool
.entropy
);
627 subtract_entropy(ent
, deltae
);
628 add_pseudo(ent
, count
* 8);
632 memset(digest
, 0, sizeof(digest
));
634 if (returned
!= NULL
)
635 *returned
= (length
- remain
);
639 return (ISC_R_SUCCESS
);
642 /* put the entropy we almost extracted back */
643 add_entropy(ent
, total
);
644 memset(data
, 0, length
);
645 memset(digest
, 0, sizeof(digest
));
646 if (returned
!= NULL
)
651 return (ISC_R_NOENTROPY
);
655 isc_entropypool_init(isc_entropypool_t
*pool
) {
656 pool
->cursor
= RND_POOLWORDS
- 1;
660 memset(pool
->pool
, 0, RND_POOLBYTES
);
664 isc_entropypool_invalidate(isc_entropypool_t
*pool
) {
669 memset(pool
->pool
, 0, RND_POOLBYTES
);
673 isc_entropy_create(isc_mem_t
*mctx
, isc_entropy_t
**entp
) {
677 REQUIRE(mctx
!= NULL
);
678 REQUIRE(entp
!= NULL
&& *entp
== NULL
);
680 ent
= isc_mem_get(mctx
, sizeof(isc_entropy_t
));
682 return (ISC_R_NOMEMORY
);
687 result
= isc_mutex_init(&ent
->lock
);
688 if (result
!= ISC_R_SUCCESS
)
692 * From here down, no failures will/can occur.
694 ISC_LIST_INIT(ent
->sources
);
695 ent
->nextsource
= NULL
;
698 isc_mem_attach(mctx
, &ent
->mctx
);
700 ent
->initialized
= 0;
702 ent
->magic
= ENTROPY_MAGIC
;
704 isc_entropypool_init(&ent
->pool
);
707 return (ISC_R_SUCCESS
);
710 isc_mem_put(mctx
, ent
, sizeof(isc_entropy_t
));
716 * Requires "ent" be locked.
719 destroysource(isc_entropysource_t
**sourcep
) {
720 isc_entropysource_t
*source
;
728 ISC_LIST_UNLINK(ent
->sources
, source
, link
);
729 ent
->nextsource
= NULL
;
730 REQUIRE(ent
->nsources
> 0);
733 switch (source
->type
) {
734 case ENTROPY_SOURCETYPE_FILE
:
736 destroyfilesource(&source
->sources
.file
);
738 case ENTROPY_SOURCETYPE_USOCKET
:
740 destroyusocketsource(&source
->sources
.usocket
);
742 case ENTROPY_SOURCETYPE_SAMPLE
:
743 samplequeue_release(ent
, &source
->sources
.sample
.samplequeue
);
745 case ENTROPY_SOURCETYPE_CALLBACK
:
746 cbs
= &source
->sources
.callback
;
747 if (cbs
->start_called
&& cbs
->stopfunc
!= NULL
) {
748 cbs
->stopfunc(source
, cbs
->arg
);
749 cbs
->start_called
= ISC_FALSE
;
751 samplequeue_release(ent
, &cbs
->samplequeue
);
755 memset(source
, 0, sizeof(isc_entropysource_t
));
757 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));
760 static inline isc_boolean_t
761 destroy_check(isc_entropy_t
*ent
) {
762 isc_entropysource_t
*source
;
767 source
= ISC_LIST_HEAD(ent
->sources
);
768 while (source
!= NULL
) {
769 switch (source
->type
) {
770 case ENTROPY_SOURCETYPE_FILE
:
771 case ENTROPY_SOURCETYPE_USOCKET
:
776 source
= ISC_LIST_NEXT(source
, link
);
783 destroy(isc_entropy_t
**entp
) {
785 isc_entropysource_t
*source
;
788 REQUIRE(entp
!= NULL
&& *entp
!= NULL
);
794 REQUIRE(ent
->refcnt
== 0);
797 * Here, detach non-sample sources.
799 source
= ISC_LIST_HEAD(ent
->sources
);
800 while (source
!= NULL
) {
801 switch(source
->type
) {
802 case ENTROPY_SOURCETYPE_FILE
:
803 case ENTROPY_SOURCETYPE_USOCKET
:
804 destroysource(&source
);
807 source
= ISC_LIST_HEAD(ent
->sources
);
811 * If there are other types of sources, we've found a bug.
813 REQUIRE(ISC_LIST_EMPTY(ent
->sources
));
817 isc_entropypool_invalidate(&ent
->pool
);
821 DESTROYLOCK(&ent
->lock
);
823 memset(ent
, 0, sizeof(isc_entropy_t
));
824 isc_mem_put(mctx
, ent
, sizeof(isc_entropy_t
));
825 isc_mem_detach(&mctx
);
829 isc_entropy_destroysource(isc_entropysource_t
**sourcep
) {
830 isc_entropysource_t
*source
;
832 isc_boolean_t killit
;
834 REQUIRE(sourcep
!= NULL
);
835 REQUIRE(VALID_SOURCE(*sourcep
));
841 REQUIRE(VALID_ENTROPY(ent
));
845 destroysource(&source
);
847 killit
= destroy_check(ent
);
856 isc_entropy_createcallbacksource(isc_entropy_t
*ent
,
857 isc_entropystart_t start
,
858 isc_entropyget_t get
,
859 isc_entropystop_t stop
,
861 isc_entropysource_t
**sourcep
)
864 isc_entropysource_t
*source
;
867 REQUIRE(VALID_ENTROPY(ent
));
868 REQUIRE(get
!= NULL
);
869 REQUIRE(sourcep
!= NULL
&& *sourcep
== NULL
);
873 source
= isc_mem_get(ent
->mctx
, sizeof(isc_entropysource_t
));
874 if (source
== NULL
) {
875 result
= ISC_R_NOMEMORY
;
878 source
->bad
= ISC_FALSE
;
880 cbs
= &source
->sources
.callback
;
882 result
= samplesource_allocate(ent
, &cbs
->samplequeue
);
883 if (result
!= ISC_R_SUCCESS
)
886 cbs
->start_called
= ISC_FALSE
;
887 cbs
->startfunc
= start
;
889 cbs
->stopfunc
= stop
;
893 * From here down, no failures can occur.
895 source
->magic
= SOURCE_MAGIC
;
896 source
->type
= ENTROPY_SOURCETYPE_CALLBACK
;
899 memset(source
->name
, 0, sizeof(source
->name
));
900 ISC_LINK_INIT(source
, link
);
903 * Hook it into the entropy system.
905 ISC_LIST_APPEND(ent
->sources
, source
, link
);
911 return (ISC_R_SUCCESS
);
915 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));
923 isc_entropy_stopcallbacksources(isc_entropy_t
*ent
) {
924 isc_entropysource_t
*source
;
927 REQUIRE(VALID_ENTROPY(ent
));
931 source
= ISC_LIST_HEAD(ent
->sources
);
932 while (source
!= NULL
) {
933 if (source
->type
== ENTROPY_SOURCETYPE_CALLBACK
) {
934 cbs
= &source
->sources
.callback
;
935 if (cbs
->start_called
&& cbs
->stopfunc
!= NULL
) {
936 cbs
->stopfunc(source
, cbs
->arg
);
937 cbs
->start_called
= ISC_FALSE
;
941 source
= ISC_LIST_NEXT(source
, link
);
948 isc_entropy_createsamplesource(isc_entropy_t
*ent
,
949 isc_entropysource_t
**sourcep
)
952 isc_entropysource_t
*source
;
955 REQUIRE(VALID_ENTROPY(ent
));
956 REQUIRE(sourcep
!= NULL
&& *sourcep
== NULL
);
960 source
= isc_mem_get(ent
->mctx
, sizeof(isc_entropysource_t
));
961 if (source
== NULL
) {
962 result
= ISC_R_NOMEMORY
;
966 sq
= &source
->sources
.sample
.samplequeue
;
967 result
= samplesource_allocate(ent
, sq
);
968 if (result
!= ISC_R_SUCCESS
)
972 * From here down, no failures can occur.
974 source
->magic
= SOURCE_MAGIC
;
975 source
->type
= ENTROPY_SOURCETYPE_SAMPLE
;
978 memset(source
->name
, 0, sizeof(source
->name
));
979 ISC_LINK_INIT(source
, link
);
982 * Hook it into the entropy system.
984 ISC_LIST_APPEND(ent
->sources
, source
, link
);
990 return (ISC_R_SUCCESS
);
994 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));
1002 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1003 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1004 * queue was full when this function was called.
1007 addsample(sample_queue_t
*sq
, isc_uint32_t sample
, isc_uint32_t extra
) {
1008 if (sq
->nsamples
>= RND_EVENTQSIZE
)
1009 return (ISC_R_NOMORE
);
1011 sq
->samples
[sq
->nsamples
] = sample
;
1012 sq
->extra
[sq
->nsamples
] = extra
;
1015 if (sq
->nsamples
>= RND_EVENTQSIZE
)
1016 return (ISC_R_QUEUEFULL
);
1018 return (ISC_R_SUCCESS
);
1022 isc_entropy_addsample(isc_entropysource_t
*source
, isc_uint32_t sample
,
1027 unsigned int entropy
;
1028 isc_result_t result
;
1030 REQUIRE(VALID_SOURCE(source
));
1036 sq
= &source
->sources
.sample
.samplequeue
;
1037 result
= addsample(sq
, sample
, extra
);
1038 if (result
== ISC_R_QUEUEFULL
) {
1039 entropy
= crunchsamples(ent
, sq
);
1040 add_entropy(ent
, entropy
);
1049 isc_entropy_addcallbacksample(isc_entropysource_t
*source
, isc_uint32_t sample
,
1053 isc_result_t result
;
1055 REQUIRE(VALID_SOURCE(source
));
1056 REQUIRE(source
->type
== ENTROPY_SOURCETYPE_CALLBACK
);
1058 sq
= &source
->sources
.callback
.samplequeue
;
1059 result
= addsample(sq
, sample
, extra
);
1065 isc_entropy_putdata(isc_entropy_t
*ent
, void *data
, unsigned int length
,
1066 isc_uint32_t entropy
)
1068 REQUIRE(VALID_ENTROPY(ent
));
1072 entropypool_adddata(ent
, data
, length
, entropy
);
1074 if (ent
->initialized
< THRESHOLD_BITS
)
1075 ent
->initialized
= THRESHOLD_BITS
;
1081 dumpstats(isc_entropy_t
*ent
, FILE *out
) {
1083 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_ENTROPY
,
1084 ISC_MSG_ENTROPYSTATS
,
1085 "Entropy pool %p: refcnt %u cursor %u,"
1086 " rotate %u entropy %u pseudo %u nsources %u"
1087 " nextsource %p initialized %u initcount %u\n"),
1089 ent
->pool
.cursor
, ent
->pool
.rotate
,
1090 ent
->pool
.entropy
, ent
->pool
.pseudo
,
1091 ent
->nsources
, ent
->nextsource
, ent
->initialized
,
1096 * This function ignores locking. Use at your own risk.
1099 isc_entropy_stats(isc_entropy_t
*ent
, FILE *out
) {
1100 REQUIRE(VALID_ENTROPY(ent
));
1103 dumpstats(ent
, out
);
1108 isc_entropy_status(isc_entropy_t
*ent
) {
1109 unsigned int estimate
;
1112 estimate
= ent
->pool
.entropy
;
1119 isc_entropy_attach(isc_entropy_t
*ent
, isc_entropy_t
**entp
) {
1120 REQUIRE(VALID_ENTROPY(ent
));
1121 REQUIRE(entp
!= NULL
&& *entp
== NULL
);
1132 isc_entropy_detach(isc_entropy_t
**entp
) {
1134 isc_boolean_t killit
;
1136 REQUIRE(entp
!= NULL
&& VALID_ENTROPY(*entp
));
1142 REQUIRE(ent
->refcnt
> 0);
1145 killit
= destroy_check(ent
);
1154 kbdstart(isc_entropysource_t
*source
, void *arg
, isc_boolean_t blocking
) {
1156 * The intent of "first" is to provide a warning message only once
1157 * during the run of a program that might try to gather keyboard
1158 * entropy multiple times.
1160 static isc_boolean_t first
= ISC_TRUE
;
1165 return (ISC_R_NOENTROPY
);
1168 if (source
->warn_keyboard
)
1169 fprintf(stderr
, "You must use the keyboard to create "
1170 "entropy, since your system is lacking\n"
1171 "/dev/random (or equivalent)\n\n");
1174 fprintf(stderr
, "start typing:\n");
1176 return (isc_keyboard_open(&source
->kbd
));
1180 kbdstop(isc_entropysource_t
*source
, void *arg
) {
1184 if (! isc_keyboard_canceled(&source
->kbd
))
1185 fprintf(stderr
, "stop typing.\r\n");
1187 (void)isc_keyboard_close(&source
->kbd
, 3);
1191 kbdget(isc_entropysource_t
*source
, void *arg
, isc_boolean_t blocking
) {
1192 isc_result_t result
;
1194 isc_uint32_t sample
;
1201 return (ISC_R_NOTBLOCKING
);
1203 result
= isc_keyboard_getchar(&source
->kbd
, &c
);
1204 if (result
!= ISC_R_SUCCESS
)
1209 sample
= isc_time_nanoseconds(&t
);
1212 result
= isc_entropy_addcallbacksample(source
, sample
, extra
);
1213 if (result
!= ISC_R_SUCCESS
) {
1214 fprintf(stderr
, "\r\n");
1218 fprintf(stderr
, ".");
1225 isc_entropy_usebestsource(isc_entropy_t
*ectx
, isc_entropysource_t
**source
,
1226 const char *randomfile
, int use_keyboard
)
1228 isc_result_t result
;
1229 isc_result_t final_result
= ISC_R_NOENTROPY
;
1230 isc_boolean_t userfile
= ISC_TRUE
;
1232 REQUIRE(VALID_ENTROPY(ectx
));
1233 REQUIRE(source
!= NULL
&& *source
== NULL
);
1234 REQUIRE(use_keyboard
== ISC_ENTROPY_KEYBOARDYES
||
1235 use_keyboard
== ISC_ENTROPY_KEYBOARDNO
||
1236 use_keyboard
== ISC_ENTROPY_KEYBOARDMAYBE
);
1238 #ifdef PATH_RANDOMDEV
1239 if (randomfile
== NULL
) {
1240 randomfile
= PATH_RANDOMDEV
;
1241 userfile
= ISC_FALSE
;
1245 if (randomfile
!= NULL
&& use_keyboard
!= ISC_ENTROPY_KEYBOARDYES
) {
1246 result
= isc_entropy_createfilesource(ectx
, randomfile
);
1247 if (result
== ISC_R_SUCCESS
&&
1248 use_keyboard
== ISC_ENTROPY_KEYBOARDMAYBE
)
1249 use_keyboard
= ISC_ENTROPY_KEYBOARDNO
;
1250 if (result
!= ISC_R_SUCCESS
&& userfile
)
1253 final_result
= result
;
1256 if (use_keyboard
!= ISC_ENTROPY_KEYBOARDNO
) {
1257 result
= isc_entropy_createcallbacksource(ectx
, kbdstart
,
1260 if (result
== ISC_R_SUCCESS
)
1261 (*source
)->warn_keyboard
=
1262 ISC_TF(use_keyboard
==
1263 ISC_ENTROPY_KEYBOARDMAYBE
);
1265 if (final_result
!= ISC_R_SUCCESS
)
1266 final_result
= result
;
1270 * final_result is ISC_R_SUCCESS if at least one source of entropy
1271 * could be started, otherwise it is the error from the most recently
1272 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1273 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1275 return (final_result
);