2 * Copyright (C) 2004-2007, 2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.18.128.2 2009/01/19 23:47:03 tbox Exp $ */
22 * This is the system independent part of the entropy module. It is
23 * compiled via inclusion from the relevant OS source file, ie,
24 * \link unix/entropy.c unix/entropy.c \endlink or win32/entropy.c.
26 * \author Much of this code is modeled after the NetBSD /dev/random implementation,
27 * written by Michael Graff <explorer@netbsd.org>.
34 #include <isc/buffer.h>
35 #include <isc/entropy.h>
36 #include <isc/keyboard.h>
38 #include <isc/magic.h>
41 #include <isc/mutex.h>
42 #include <isc/platform.h>
43 #include <isc/region.h>
45 #include <isc/string.h>
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
66 #define RND_POOLBYTES (RND_POOLWORDS * 4)
68 #define RND_POOLBITS (RND_POOLWORDS * 32)
71 * Number of bytes returned per hash. This must be true:
72 * threshold * 2 <= digest_size_in_bytes
74 #define RND_ENTROPY_THRESHOLD 10
75 #define THRESHOLD_BITS (RND_ENTROPY_THRESHOLD * 8)
78 * Size of the input event queue in samples.
80 #define RND_EVENTQSIZE 32
83 * The number of times we'll "reseed" for pseudorandom seeds. This is an
84 * extremely weak pseudorandom seed. If the caller is using lots of
85 * pseudorandom data and they cannot provide a stronger random source,
86 * there is little we can do other than hope they're smart enough to
87 * call _adddata() with something better than we can come up with.
89 #define RND_INITIALIZE 128
93 isc_uint32_t cursor
; /*%< current add point in the pool */
94 isc_uint32_t entropy
; /*%< current entropy estimate in bits */
95 isc_uint32_t pseudo
; /*%< bits extracted in pseudorandom */
96 isc_uint32_t rotate
; /*%< how many bits to rotate by */
97 isc_uint32_t pool
[RND_POOLWORDS
]; /*%< random pool data */
105 isc_uint32_t initialized
;
106 isc_uint32_t initcount
;
107 isc_entropypool_t pool
;
108 unsigned int nsources
;
109 isc_entropysource_t
*nextsource
;
110 ISC_LIST(isc_entropysource_t
) sources
;
115 isc_uint32_t last_time
; /*%< last time recorded */
116 isc_uint32_t last_delta
; /*%< last delta value */
117 isc_uint32_t last_delta2
; /*%< last delta2 value */
118 isc_uint32_t nsamples
; /*%< number of samples filled in */
119 isc_uint32_t
*samples
; /*%< the samples */
120 isc_uint32_t
*extra
; /*%< extra samples added in */
124 sample_queue_t samplequeue
;
125 } isc_entropysamplesource_t
;
128 isc_boolean_t start_called
;
129 isc_entropystart_t startfunc
;
130 isc_entropyget_t getfunc
;
131 isc_entropystop_t stopfunc
;
133 sample_queue_t samplequeue
;
137 FILESOURCE_HANDLE_TYPE handle
;
138 } isc_entropyfilesource_t
;
140 struct isc_entropysource
{
144 isc_uint32_t total
; /*%< entropy from this source */
145 ISC_LINK(isc_entropysource_t
) link
;
148 isc_boolean_t warn_keyboard
;
151 isc_entropysamplesource_t sample
;
152 isc_entropyfilesource_t file
;
153 isc_cbsource_t callback
;
154 isc_entropyusocketsource_t usocket
;
158 #define ENTROPY_SOURCETYPE_SAMPLE 1 /*%< Type is a sample source */
159 #define ENTROPY_SOURCETYPE_FILE 2 /*%< Type is a file source */
160 #define ENTROPY_SOURCETYPE_CALLBACK 3 /*%< Type is a callback source */
161 #define ENTROPY_SOURCETYPE_USOCKET 4 /*%< Type is a Unix socket source */
165 * The random pool "taps"
176 * Declarations for function provided by the system dependent sources that
180 fillpool(isc_entropy_t
*, unsigned int, isc_boolean_t
);
183 wait_for_sources(isc_entropy_t
*);
186 destroyfilesource(isc_entropyfilesource_t
*source
);
189 destroyusocketsource(isc_entropyusocketsource_t
*source
);
194 samplequeue_release(isc_entropy_t
*ent
, sample_queue_t
*sq
) {
195 REQUIRE(sq
->samples
!= NULL
);
196 REQUIRE(sq
->extra
!= NULL
);
198 isc_mem_put(ent
->mctx
, sq
->samples
, RND_EVENTQSIZE
* 4);
199 isc_mem_put(ent
->mctx
, sq
->extra
, RND_EVENTQSIZE
* 4);
205 samplesource_allocate(isc_entropy_t
*ent
, sample_queue_t
*sq
) {
206 sq
->samples
= isc_mem_get(ent
->mctx
, RND_EVENTQSIZE
* 4);
207 if (sq
->samples
== NULL
)
208 return (ISC_R_NOMEMORY
);
210 sq
->extra
= isc_mem_get(ent
->mctx
, RND_EVENTQSIZE
* 4);
211 if (sq
->extra
== NULL
) {
212 isc_mem_put(ent
->mctx
, sq
->samples
, RND_EVENTQSIZE
* 4);
214 return (ISC_R_NOMEMORY
);
219 return (ISC_R_SUCCESS
);
223 * Add in entropy, even when the value we're adding in could be
227 add_entropy(isc_entropy_t
*ent
, isc_uint32_t entropy
) {
228 /* clamp input. Yes, this must be done. */
229 entropy
= ISC_MIN(entropy
, RND_POOLBITS
);
230 /* Add in the entropy we already have. */
231 entropy
+= ent
->pool
.entropy
;
233 ent
->pool
.entropy
= ISC_MIN(entropy
, RND_POOLBITS
);
237 * Decrement the amount of entropy the pool has.
240 subtract_entropy(isc_entropy_t
*ent
, isc_uint32_t entropy
) {
241 entropy
= ISC_MIN(entropy
, ent
->pool
.entropy
);
242 ent
->pool
.entropy
-= entropy
;
246 * Add in entropy, even when the value we're adding in could be
250 add_pseudo(isc_entropy_t
*ent
, isc_uint32_t pseudo
) {
251 /* clamp input. Yes, this must be done. */
252 pseudo
= ISC_MIN(pseudo
, RND_POOLBITS
* 8);
253 /* Add in the pseudo we already have. */
254 pseudo
+= ent
->pool
.pseudo
;
256 ent
->pool
.pseudo
= ISC_MIN(pseudo
, RND_POOLBITS
* 8);
260 * Decrement the amount of pseudo the pool has.
263 subtract_pseudo(isc_entropy_t
*ent
, isc_uint32_t pseudo
) {
264 pseudo
= ISC_MIN(pseudo
, ent
->pool
.pseudo
);
265 ent
->pool
.pseudo
-= pseudo
;
269 * Add one word to the pool, rotating the input as needed.
272 entropypool_add_word(isc_entropypool_t
*rp
, isc_uint32_t val
) {
274 * Steal some values out of the pool, and xor them into the
275 * word we were given.
277 * Mix the new value into the pool using xor. This will
278 * prevent the actual values from being known to the caller
279 * since the previous values are assumed to be unknown as well.
281 val
^= rp
->pool
[(rp
->cursor
+ TAP1
) & (RND_POOLWORDS
- 1)];
282 val
^= rp
->pool
[(rp
->cursor
+ TAP2
) & (RND_POOLWORDS
- 1)];
283 val
^= rp
->pool
[(rp
->cursor
+ TAP3
) & (RND_POOLWORDS
- 1)];
284 val
^= rp
->pool
[(rp
->cursor
+ TAP4
) & (RND_POOLWORDS
- 1)];
285 val
^= rp
->pool
[(rp
->cursor
+ TAP5
) & (RND_POOLWORDS
- 1)];
286 rp
->pool
[rp
->cursor
++] ^=
287 ((val
<< rp
->rotate
) | (val
>> (32 - rp
->rotate
)));
290 * If we have looped around the pool, increment the rotate
291 * variable so the next value will get xored in rotated to
292 * a different position.
293 * Increment by a value that is relatively prime to the word size
294 * to try to spread the bits throughout the pool quickly when the
297 if (rp
->cursor
== RND_POOLWORDS
) {
299 rp
->rotate
= (rp
->rotate
+ 7) & 31;
304 * Add a buffer's worth of data to the pool.
306 * Requires that the lock is held on the entropy pool.
309 entropypool_adddata(isc_entropy_t
*ent
, void *p
, unsigned int len
,
310 isc_uint32_t entropy
)
316 addr
= (unsigned long)p
;
319 if ((addr
& 0x03U
) != 0U) {
326 val
= val
<< 8 | *buf
++;
329 val
= val
<< 8 | *buf
++;
333 entropypool_add_word(&ent
->pool
, val
);
336 for (; len
> 3; len
-= 4) {
337 val
= *((isc_uint32_t
*)buf
);
339 entropypool_add_word(&ent
->pool
, val
);
349 val
= val
<< 8 | *buf
++;
351 val
= val
<< 8 | *buf
++;
354 entropypool_add_word(&ent
->pool
, val
);
357 add_entropy(ent
, entropy
);
358 subtract_pseudo(ent
, entropy
);
362 reseed(isc_entropy_t
*ent
) {
366 if (ent
->initcount
== 0) {
368 entropypool_adddata(ent
, &pid
, sizeof(pid
), 0);
370 entropypool_adddata(ent
, &pid
, sizeof(pid
), 0);
374 * After we've reseeded 100 times, only add new timing info every
375 * 50 requests. This will keep us from using lots and lots of
376 * CPU just to return bad pseudorandom data anyway.
378 if (ent
->initcount
> 100)
379 if ((ent
->initcount
% 50) != 0)
383 entropypool_adddata(ent
, &t
, sizeof(t
), 0);
387 static inline unsigned int
388 estimate_entropy(sample_queue_t
*sq
, isc_uint32_t t
) {
394 * If the time counter has overflowed, calculate the real difference.
395 * If it has not, it is simpler.
397 if (t
< sq
->last_time
)
398 delta
= UINT_MAX
- sq
->last_time
+ t
;
400 delta
= sq
->last_time
- t
;
406 * Calculate the second and third order differentials
408 delta2
= sq
->last_delta
- delta
;
412 delta3
= sq
->last_delta2
- delta2
;
417 sq
->last_delta
= delta
;
418 sq
->last_delta2
= delta2
;
421 * If any delta is 0, we got no entropy. If all are non-zero, we
422 * might have something.
424 if (delta
== 0 || delta2
== 0 || delta3
== 0)
428 * We could find the smallest delta and claim we got log2(delta)
429 * bits, but for now return that we found 1 bit.
435 crunchsamples(isc_entropy_t
*ent
, sample_queue_t
*sq
) {
439 if (sq
->nsamples
< 6)
443 sq
->last_time
= sq
->samples
[0];
448 * Prime the values by adding in the first 4 samples in. This
449 * should completely initialize the delta calculations.
451 for (ns
= 0; ns
< 4; ns
++)
452 (void)estimate_entropy(sq
, sq
->samples
[ns
]);
454 for (ns
= 4; ns
< sq
->nsamples
; ns
++)
455 added
+= estimate_entropy(sq
, sq
->samples
[ns
]);
457 entropypool_adddata(ent
, sq
->samples
, sq
->nsamples
* 4, added
);
458 entropypool_adddata(ent
, sq
->extra
, sq
->nsamples
* 4, 0);
461 * Move the last 4 samples into the first 4 positions, and start
462 * adding new samples from that point.
464 for (ns
= 0; ns
< 4; ns
++) {
465 sq
->samples
[ns
] = sq
->samples
[sq
->nsamples
- 4 + ns
];
466 sq
->extra
[ns
] = sq
->extra
[sq
->nsamples
- 4 + ns
];
475 get_from_callback(isc_entropysource_t
*source
, unsigned int desired
,
476 isc_boolean_t blocking
)
478 isc_entropy_t
*ent
= source
->ent
;
479 isc_cbsource_t
*cbs
= &source
->sources
.callback
;
490 if (!cbs
->start_called
&& cbs
->startfunc
!= NULL
) {
491 result
= cbs
->startfunc(source
, cbs
->arg
, blocking
);
492 if (result
!= ISC_R_SUCCESS
)
494 cbs
->start_called
= ISC_TRUE
;
498 result
= ISC_R_SUCCESS
;
499 while (desired
> 0 && result
== ISC_R_SUCCESS
) {
500 result
= cbs
->getfunc(source
, cbs
->arg
, blocking
);
501 if (result
== ISC_R_QUEUEFULL
) {
502 got
= crunchsamples(ent
, &cbs
->samplequeue
);
504 desired
-= ISC_MIN(got
, desired
);
505 result
= ISC_R_SUCCESS
;
506 } else if (result
!= ISC_R_SUCCESS
&&
507 result
!= ISC_R_NOTBLOCKING
)
508 source
->bad
= ISC_TRUE
;
516 * Extract some number of bytes from the random pool, decreasing the
517 * estimate of randomness as each byte is extracted.
519 * Do this by stiring the pool and returning a part of hash as randomness.
520 * Note that no secrets are given away here since parts of the hash are
521 * xored together before returned.
523 * Honor the request from the caller to only return good data, any data,
527 isc_entropy_getdata(isc_entropy_t
*ent
, void *data
, unsigned int length
,
528 unsigned int *returned
, unsigned int flags
)
532 unsigned char digest
[ISC_SHA1_DIGESTLENGTH
];
533 isc_uint32_t remain
, deltae
, count
, total
;
535 isc_boolean_t goodonly
, partial
, blocking
;
537 REQUIRE(VALID_ENTROPY(ent
));
538 REQUIRE(data
!= NULL
);
541 goodonly
= ISC_TF((flags
& ISC_ENTROPY_GOODONLY
) != 0);
542 partial
= ISC_TF((flags
& ISC_ENTROPY_PARTIAL
) != 0);
543 blocking
= ISC_TF((flags
& ISC_ENTROPY_BLOCKING
) != 0);
545 REQUIRE(!partial
|| returned
!= NULL
);
552 while (remain
!= 0) {
553 count
= ISC_MIN(remain
, RND_ENTROPY_THRESHOLD
);
556 * If we are extracting good data only, make certain we
557 * have enough data in our pool for this pass. If we don't,
558 * get some, and fail if we can't, and partial returns
562 unsigned int fillcount
;
564 fillcount
= ISC_MAX(remain
* 8, count
* 8);
567 * If, however, we have at least THRESHOLD_BITS
568 * of entropy in the pool, don't block here. It is
569 * better to drain the pool once in a while and
570 * then refill it than it is to constantly keep the
573 if (ent
->pool
.entropy
>= THRESHOLD_BITS
)
574 fillpool(ent
, fillcount
, ISC_FALSE
);
576 fillpool(ent
, fillcount
, blocking
);
579 * Verify that we got enough entropy to do one
580 * extraction. If we didn't, bail.
582 if (ent
->pool
.entropy
< THRESHOLD_BITS
) {
590 * If we've extracted half our pool size in bits
591 * since the last refresh, try to refresh here.
593 if (ent
->initialized
< THRESHOLD_BITS
)
594 fillpool(ent
, THRESHOLD_BITS
, blocking
);
596 fillpool(ent
, 0, ISC_FALSE
);
599 * If we've not initialized with enough good random
600 * data, seed with our crappy code.
602 if (ent
->initialized
< THRESHOLD_BITS
)
606 isc_sha1_init(&hash
);
607 isc_sha1_update(&hash
, (void *)(ent
->pool
.pool
),
609 isc_sha1_final(&hash
, digest
);
612 * Stir the extracted data (all of it) back into the pool.
614 entropypool_adddata(ent
, digest
, ISC_SHA1_DIGESTLENGTH
, 0);
616 for (i
= 0; i
< count
; i
++)
617 buf
[i
] = digest
[i
] ^ digest
[i
+ RND_ENTROPY_THRESHOLD
];
623 deltae
= ISC_MIN(deltae
, ent
->pool
.entropy
);
625 subtract_entropy(ent
, deltae
);
626 add_pseudo(ent
, count
* 8);
630 memset(digest
, 0, sizeof(digest
));
632 if (returned
!= NULL
)
633 *returned
= (length
- remain
);
637 return (ISC_R_SUCCESS
);
640 /* put the entropy we almost extracted back */
641 add_entropy(ent
, total
);
642 memset(data
, 0, length
);
643 memset(digest
, 0, sizeof(digest
));
644 if (returned
!= NULL
)
649 return (ISC_R_NOENTROPY
);
653 isc_entropypool_init(isc_entropypool_t
*pool
) {
654 pool
->cursor
= RND_POOLWORDS
- 1;
658 memset(pool
->pool
, 0, RND_POOLBYTES
);
662 isc_entropypool_invalidate(isc_entropypool_t
*pool
) {
667 memset(pool
->pool
, 0, RND_POOLBYTES
);
671 isc_entropy_create(isc_mem_t
*mctx
, isc_entropy_t
**entp
) {
675 REQUIRE(mctx
!= NULL
);
676 REQUIRE(entp
!= NULL
&& *entp
== NULL
);
678 ent
= isc_mem_get(mctx
, sizeof(isc_entropy_t
));
680 return (ISC_R_NOMEMORY
);
685 result
= isc_mutex_init(&ent
->lock
);
686 if (result
!= ISC_R_SUCCESS
)
690 * From here down, no failures will/can occur.
692 ISC_LIST_INIT(ent
->sources
);
693 ent
->nextsource
= NULL
;
696 isc_mem_attach(mctx
, &ent
->mctx
);
698 ent
->initialized
= 0;
700 ent
->magic
= ENTROPY_MAGIC
;
702 isc_entropypool_init(&ent
->pool
);
705 return (ISC_R_SUCCESS
);
708 isc_mem_put(mctx
, ent
, sizeof(isc_entropy_t
));
714 * Requires "ent" be locked.
717 destroysource(isc_entropysource_t
**sourcep
) {
718 isc_entropysource_t
*source
;
726 ISC_LIST_UNLINK(ent
->sources
, source
, link
);
727 ent
->nextsource
= NULL
;
728 REQUIRE(ent
->nsources
> 0);
731 switch (source
->type
) {
732 case ENTROPY_SOURCETYPE_FILE
:
734 destroyfilesource(&source
->sources
.file
);
736 case ENTROPY_SOURCETYPE_USOCKET
:
738 destroyusocketsource(&source
->sources
.usocket
);
740 case ENTROPY_SOURCETYPE_SAMPLE
:
741 samplequeue_release(ent
, &source
->sources
.sample
.samplequeue
);
743 case ENTROPY_SOURCETYPE_CALLBACK
:
744 cbs
= &source
->sources
.callback
;
745 if (cbs
->start_called
&& cbs
->stopfunc
!= NULL
) {
746 cbs
->stopfunc(source
, cbs
->arg
);
747 cbs
->start_called
= ISC_FALSE
;
749 samplequeue_release(ent
, &cbs
->samplequeue
);
753 memset(source
, 0, sizeof(isc_entropysource_t
));
755 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));
758 static inline isc_boolean_t
759 destroy_check(isc_entropy_t
*ent
) {
760 isc_entropysource_t
*source
;
765 source
= ISC_LIST_HEAD(ent
->sources
);
766 while (source
!= NULL
) {
767 switch (source
->type
) {
768 case ENTROPY_SOURCETYPE_FILE
:
769 case ENTROPY_SOURCETYPE_USOCKET
:
774 source
= ISC_LIST_NEXT(source
, link
);
781 destroy(isc_entropy_t
**entp
) {
783 isc_entropysource_t
*source
;
786 REQUIRE(entp
!= NULL
&& *entp
!= NULL
);
792 REQUIRE(ent
->refcnt
== 0);
795 * Here, detach non-sample sources.
797 source
= ISC_LIST_HEAD(ent
->sources
);
798 while (source
!= NULL
) {
799 switch(source
->type
) {
800 case ENTROPY_SOURCETYPE_FILE
:
801 case ENTROPY_SOURCETYPE_USOCKET
:
802 destroysource(&source
);
805 source
= ISC_LIST_HEAD(ent
->sources
);
809 * If there are other types of sources, we've found a bug.
811 REQUIRE(ISC_LIST_EMPTY(ent
->sources
));
815 isc_entropypool_invalidate(&ent
->pool
);
819 DESTROYLOCK(&ent
->lock
);
821 memset(ent
, 0, sizeof(isc_entropy_t
));
822 isc_mem_put(mctx
, ent
, sizeof(isc_entropy_t
));
823 isc_mem_detach(&mctx
);
827 isc_entropy_destroysource(isc_entropysource_t
**sourcep
) {
828 isc_entropysource_t
*source
;
830 isc_boolean_t killit
;
832 REQUIRE(sourcep
!= NULL
);
833 REQUIRE(VALID_SOURCE(*sourcep
));
839 REQUIRE(VALID_ENTROPY(ent
));
843 destroysource(&source
);
845 killit
= destroy_check(ent
);
854 isc_entropy_createcallbacksource(isc_entropy_t
*ent
,
855 isc_entropystart_t start
,
856 isc_entropyget_t get
,
857 isc_entropystop_t stop
,
859 isc_entropysource_t
**sourcep
)
862 isc_entropysource_t
*source
;
865 REQUIRE(VALID_ENTROPY(ent
));
866 REQUIRE(get
!= NULL
);
867 REQUIRE(sourcep
!= NULL
&& *sourcep
== NULL
);
871 source
= isc_mem_get(ent
->mctx
, sizeof(isc_entropysource_t
));
872 if (source
== NULL
) {
873 result
= ISC_R_NOMEMORY
;
876 source
->bad
= ISC_FALSE
;
878 cbs
= &source
->sources
.callback
;
880 result
= samplesource_allocate(ent
, &cbs
->samplequeue
);
881 if (result
!= ISC_R_SUCCESS
)
884 cbs
->start_called
= ISC_FALSE
;
885 cbs
->startfunc
= start
;
887 cbs
->stopfunc
= stop
;
891 * From here down, no failures can occur.
893 source
->magic
= SOURCE_MAGIC
;
894 source
->type
= ENTROPY_SOURCETYPE_CALLBACK
;
897 memset(source
->name
, 0, sizeof(source
->name
));
898 ISC_LINK_INIT(source
, link
);
901 * Hook it into the entropy system.
903 ISC_LIST_APPEND(ent
->sources
, source
, link
);
909 return (ISC_R_SUCCESS
);
913 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));
921 isc_entropy_stopcallbacksources(isc_entropy_t
*ent
) {
922 isc_entropysource_t
*source
;
925 REQUIRE(VALID_ENTROPY(ent
));
929 source
= ISC_LIST_HEAD(ent
->sources
);
930 while (source
!= NULL
) {
931 if (source
->type
== ENTROPY_SOURCETYPE_CALLBACK
) {
932 cbs
= &source
->sources
.callback
;
933 if (cbs
->start_called
&& cbs
->stopfunc
!= NULL
) {
934 cbs
->stopfunc(source
, cbs
->arg
);
935 cbs
->start_called
= ISC_FALSE
;
939 source
= ISC_LIST_NEXT(source
, link
);
946 isc_entropy_createsamplesource(isc_entropy_t
*ent
,
947 isc_entropysource_t
**sourcep
)
950 isc_entropysource_t
*source
;
953 REQUIRE(VALID_ENTROPY(ent
));
954 REQUIRE(sourcep
!= NULL
&& *sourcep
== NULL
);
958 source
= isc_mem_get(ent
->mctx
, sizeof(isc_entropysource_t
));
959 if (source
== NULL
) {
960 result
= ISC_R_NOMEMORY
;
964 sq
= &source
->sources
.sample
.samplequeue
;
965 result
= samplesource_allocate(ent
, sq
);
966 if (result
!= ISC_R_SUCCESS
)
970 * From here down, no failures can occur.
972 source
->magic
= SOURCE_MAGIC
;
973 source
->type
= ENTROPY_SOURCETYPE_SAMPLE
;
976 memset(source
->name
, 0, sizeof(source
->name
));
977 ISC_LINK_INIT(source
, link
);
980 * Hook it into the entropy system.
982 ISC_LIST_APPEND(ent
->sources
, source
, link
);
988 return (ISC_R_SUCCESS
);
992 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));
1000 * Add a sample, and return ISC_R_SUCCESS if the queue has become full,
1001 * ISC_R_NOENTROPY if it has space remaining, and ISC_R_NOMORE if the
1002 * queue was full when this function was called.
1005 addsample(sample_queue_t
*sq
, isc_uint32_t sample
, isc_uint32_t extra
) {
1006 if (sq
->nsamples
>= RND_EVENTQSIZE
)
1007 return (ISC_R_NOMORE
);
1009 sq
->samples
[sq
->nsamples
] = sample
;
1010 sq
->extra
[sq
->nsamples
] = extra
;
1013 if (sq
->nsamples
>= RND_EVENTQSIZE
)
1014 return (ISC_R_QUEUEFULL
);
1016 return (ISC_R_SUCCESS
);
1020 isc_entropy_addsample(isc_entropysource_t
*source
, isc_uint32_t sample
,
1025 unsigned int entropy
;
1026 isc_result_t result
;
1028 REQUIRE(VALID_SOURCE(source
));
1034 sq
= &source
->sources
.sample
.samplequeue
;
1035 result
= addsample(sq
, sample
, extra
);
1036 if (result
== ISC_R_QUEUEFULL
) {
1037 entropy
= crunchsamples(ent
, sq
);
1038 add_entropy(ent
, entropy
);
1047 isc_entropy_addcallbacksample(isc_entropysource_t
*source
, isc_uint32_t sample
,
1051 isc_result_t result
;
1053 REQUIRE(VALID_SOURCE(source
));
1054 REQUIRE(source
->type
== ENTROPY_SOURCETYPE_CALLBACK
);
1056 sq
= &source
->sources
.callback
.samplequeue
;
1057 result
= addsample(sq
, sample
, extra
);
1063 isc_entropy_putdata(isc_entropy_t
*ent
, void *data
, unsigned int length
,
1064 isc_uint32_t entropy
)
1066 REQUIRE(VALID_ENTROPY(ent
));
1070 entropypool_adddata(ent
, data
, length
, entropy
);
1072 if (ent
->initialized
< THRESHOLD_BITS
)
1073 ent
->initialized
= THRESHOLD_BITS
;
1079 dumpstats(isc_entropy_t
*ent
, FILE *out
) {
1081 isc_msgcat_get(isc_msgcat
, ISC_MSGSET_ENTROPY
,
1082 ISC_MSG_ENTROPYSTATS
,
1083 "Entropy pool %p: refcnt %u cursor %u,"
1084 " rotate %u entropy %u pseudo %u nsources %u"
1085 " nextsource %p initialized %u initcount %u\n"),
1087 ent
->pool
.cursor
, ent
->pool
.rotate
,
1088 ent
->pool
.entropy
, ent
->pool
.pseudo
,
1089 ent
->nsources
, ent
->nextsource
, ent
->initialized
,
1094 * This function ignores locking. Use at your own risk.
1097 isc_entropy_stats(isc_entropy_t
*ent
, FILE *out
) {
1098 REQUIRE(VALID_ENTROPY(ent
));
1101 dumpstats(ent
, out
);
1106 isc_entropy_status(isc_entropy_t
*ent
) {
1107 unsigned int estimate
;
1110 estimate
= ent
->pool
.entropy
;
1117 isc_entropy_attach(isc_entropy_t
*ent
, isc_entropy_t
**entp
) {
1118 REQUIRE(VALID_ENTROPY(ent
));
1119 REQUIRE(entp
!= NULL
&& *entp
== NULL
);
1130 isc_entropy_detach(isc_entropy_t
**entp
) {
1132 isc_boolean_t killit
;
1134 REQUIRE(entp
!= NULL
&& VALID_ENTROPY(*entp
));
1140 REQUIRE(ent
->refcnt
> 0);
1143 killit
= destroy_check(ent
);
1152 kbdstart(isc_entropysource_t
*source
, void *arg
, isc_boolean_t blocking
) {
1154 * The intent of "first" is to provide a warning message only once
1155 * during the run of a program that might try to gather keyboard
1156 * entropy multiple times.
1158 static isc_boolean_t first
= ISC_TRUE
;
1163 return (ISC_R_NOENTROPY
);
1166 if (source
->warn_keyboard
)
1167 fprintf(stderr
, "You must use the keyboard to create "
1168 "entropy, since your system is lacking\n"
1169 "/dev/random (or equivalent)\n\n");
1172 fprintf(stderr
, "start typing:\n");
1174 return (isc_keyboard_open(&source
->kbd
));
1178 kbdstop(isc_entropysource_t
*source
, void *arg
) {
1182 if (! isc_keyboard_canceled(&source
->kbd
))
1183 fprintf(stderr
, "stop typing.\r\n");
1185 (void)isc_keyboard_close(&source
->kbd
, 3);
1189 kbdget(isc_entropysource_t
*source
, void *arg
, isc_boolean_t blocking
) {
1190 isc_result_t result
;
1192 isc_uint32_t sample
;
1199 return (ISC_R_NOTBLOCKING
);
1201 result
= isc_keyboard_getchar(&source
->kbd
, &c
);
1202 if (result
!= ISC_R_SUCCESS
)
1207 sample
= isc_time_nanoseconds(&t
);
1210 result
= isc_entropy_addcallbacksample(source
, sample
, extra
);
1211 if (result
!= ISC_R_SUCCESS
) {
1212 fprintf(stderr
, "\r\n");
1216 fprintf(stderr
, ".");
1223 isc_entropy_usebestsource(isc_entropy_t
*ectx
, isc_entropysource_t
**source
,
1224 const char *randomfile
, int use_keyboard
)
1226 isc_result_t result
;
1227 isc_result_t final_result
= ISC_R_NOENTROPY
;
1228 isc_boolean_t userfile
= ISC_TRUE
;
1230 REQUIRE(VALID_ENTROPY(ectx
));
1231 REQUIRE(source
!= NULL
&& *source
== NULL
);
1232 REQUIRE(use_keyboard
== ISC_ENTROPY_KEYBOARDYES
||
1233 use_keyboard
== ISC_ENTROPY_KEYBOARDNO
||
1234 use_keyboard
== ISC_ENTROPY_KEYBOARDMAYBE
);
1236 #ifdef PATH_RANDOMDEV
1237 if (randomfile
== NULL
) {
1238 randomfile
= PATH_RANDOMDEV
;
1239 userfile
= ISC_FALSE
;
1243 if (randomfile
!= NULL
&& use_keyboard
!= ISC_ENTROPY_KEYBOARDYES
) {
1244 result
= isc_entropy_createfilesource(ectx
, randomfile
);
1245 if (result
== ISC_R_SUCCESS
&&
1246 use_keyboard
== ISC_ENTROPY_KEYBOARDMAYBE
)
1247 use_keyboard
= ISC_ENTROPY_KEYBOARDNO
;
1248 if (result
!= ISC_R_SUCCESS
&& userfile
)
1251 final_result
= result
;
1254 if (use_keyboard
!= ISC_ENTROPY_KEYBOARDNO
) {
1255 result
= isc_entropy_createcallbacksource(ectx
, kbdstart
,
1258 if (result
== ISC_R_SUCCESS
)
1259 (*source
)->warn_keyboard
=
1260 ISC_TF(use_keyboard
==
1261 ISC_ENTROPY_KEYBOARDMAYBE
);
1263 if (final_result
!= ISC_R_SUCCESS
)
1264 final_result
= result
;
1268 * final_result is ISC_R_SUCCESS if at least one source of entropy
1269 * could be started, otherwise it is the error from the most recently
1270 * failed operation (or ISC_R_NOENTROPY if PATH_RANDOMDEV is not
1271 * defined and use_keyboard is ISC_ENTROPY_KEYBOARDNO).
1273 return (final_result
);