1 /*-
2  * Copyright (c) 2010, 2014
3  *	Thorsten Glaser <tg@mirbsd.org>
4  *
5  * Provided that these terms and disclaimer and all copyright notices
6  * are retained or reproduced in an accompanying document, permission
7  * is granted to deal in this work without restriction, including un-
8  * limited rights to use, publicly perform, distribute, sell, modify,
9  * merge, give away, or sublicence.
10  *
11  * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
12  * the utmost extent permitted by applicable law, neither express nor
13  * implied; without malicious intent or gross negligence. In no event
14  * may a licensor, author or contributor be held liable for indirect,
15  * direct, other damage, loss, or other issues arising in any way out
16  * of dealing in the work, even if advised of the possibility of such
17  * damage or existence of a defect, except proven that it results out
18  * of said person's immediate fault when using the work as intended.
19  *-
20  * Implement a useful arc4random(3) related API.
21  */
22 
23 #include <syskern/libckern.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include "arc4random.h"
27 #include "thread_private.h"
28 
29 __RCSID("$MirOS: src/lib/libc/crypt/arc4random_buf.c,v 1.5 2014/03/29 10:35:46 tg Exp $");
30 
31 void
arc4random_buf(void * buf_,size_t len)32 arc4random_buf(void *buf_, size_t len)
33 {
34 	uint8_t *buf = (uint8_t *)buf_;
35 	pid_t mypid = 0;
36 	size_t n;
37 
38 	/* reinitialise if necessary */
39 	_ARC4_LOCK();
40 	if (!a4state.a4s_initialised ||
41 	    (a4state.a4s_stir_pid != (mypid = getpid())))
42 		arc4random_stir_locked(mypid);
43 	_ARC4_UNLOCK();
44 
45 	while (len) {
46 		_ARC4_LOCK();
47 		/* randomly skip 1-4 bytes */
48 		/*XXX this should be constant-time */
49 		n = arcfour_byte(&a4state.cipher) & 3;
50 		while (n--)
51 			(void)arcfour_byte(&a4state.cipher);
52 
53 		/* fill the buffer in small increments */
54 		n = len < 256 ? len : 256;
55 		len -= n;
56 		a4state.a4s_count -= n;
57 		if (a4state.a4s_count < 0)
58 			arc4random_stir_locked(mypid);
59 		while (n--)
60 			*buf++ = arcfour_byte(&a4state.cipher);
61 		_ARC4_UNLOCK();
62 	}
63 }
64