xref: /illumos-gate/usr/src/lib/libc/port/gen/arc4random.c (revision 9d12795f)
1*9d12795fSRobert Mustacchi /*
2*9d12795fSRobert Mustacchi  * Copyright (c) 1996, David Mazieres <dm@uun.org>
3*9d12795fSRobert Mustacchi  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
4*9d12795fSRobert Mustacchi  * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
5*9d12795fSRobert Mustacchi  * Copyright (c) 2015 Joyent, Inc.
6*9d12795fSRobert Mustacchi  *
7*9d12795fSRobert Mustacchi  * Permission to use, copy, modify, and distribute this software for any
8*9d12795fSRobert Mustacchi  * purpose with or without fee is hereby granted, provided that the above
9*9d12795fSRobert Mustacchi  * copyright notice and this permission notice appear in all copies.
10*9d12795fSRobert Mustacchi  *
11*9d12795fSRobert Mustacchi  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12*9d12795fSRobert Mustacchi  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13*9d12795fSRobert Mustacchi  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14*9d12795fSRobert Mustacchi  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15*9d12795fSRobert Mustacchi  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16*9d12795fSRobert Mustacchi  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17*9d12795fSRobert Mustacchi  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18*9d12795fSRobert Mustacchi  */
19*9d12795fSRobert Mustacchi 
20*9d12795fSRobert Mustacchi /*
21*9d12795fSRobert Mustacchi  * arc4random(3C), derived from the OpenBSD version.
22*9d12795fSRobert Mustacchi  *
23*9d12795fSRobert Mustacchi  * To ensure that a parent process and any potential children see a different
24*9d12795fSRobert Mustacchi  * state, we mmap the entire arc4_state_t structure and mark that page as
25*9d12795fSRobert Mustacchi  * MC_INHERIT_ZERO. That ensures that the data is zeroed, and really the bit we
26*9d12795fSRobert Mustacchi  * care about, arc4_init is set to B_FALSE, which will cause the child to
27*9d12795fSRobert Mustacchi  * reinitialize it when they first use the interface.
28*9d12795fSRobert Mustacchi  */
29*9d12795fSRobert Mustacchi 
30*9d12795fSRobert Mustacchi #include <synch.h>
31*9d12795fSRobert Mustacchi #include <stdlib.h>
32*9d12795fSRobert Mustacchi #include <string.h>
33*9d12795fSRobert Mustacchi #include <unistd.h>
34*9d12795fSRobert Mustacchi #include <sys/sysmacros.h>
35*9d12795fSRobert Mustacchi #include <chacha.h>
36*9d12795fSRobert Mustacchi 
37*9d12795fSRobert Mustacchi #include "thr_uberdata.h"
38*9d12795fSRobert Mustacchi 
39*9d12795fSRobert Mustacchi #define	ARC4_KEYSZ	32
40*9d12795fSRobert Mustacchi #define	ARC4_IVSZ	8
41*9d12795fSRobert Mustacchi #define	ARC4_BLOCKSZ	64
42*9d12795fSRobert Mustacchi #define	ARC4_KSBUFSZ	(16*ARC4_BLOCKSZ)	/* key stream byte size */
43*9d12795fSRobert Mustacchi #define	ARC4_COUNT	1600000			/* bytes for rekeying */
44*9d12795fSRobert Mustacchi 
45*9d12795fSRobert Mustacchi typedef struct arc4_state {
46*9d12795fSRobert Mustacchi 	boolean_t	arc4_init;		/* Initialized? */
47*9d12795fSRobert Mustacchi 	size_t		arc4_have;		/* Valid bytes in arc4_buf */
48*9d12795fSRobert Mustacchi 	size_t		arc4_count;		/* bytes until reseed */
49*9d12795fSRobert Mustacchi 	chacha_ctx_t	arc4_chacha;		/* chacha context */
50*9d12795fSRobert Mustacchi 	uint8_t		arc4_buf[ARC4_KSBUFSZ];	/* keystream blocks */
51*9d12795fSRobert Mustacchi } arc4_state_t;
52*9d12795fSRobert Mustacchi 
53*9d12795fSRobert Mustacchi static arc4_state_t *arc4;
54*9d12795fSRobert Mustacchi static mutex_t arc4_lock = DEFAULTMUTEX;
55*9d12795fSRobert Mustacchi 
56*9d12795fSRobert Mustacchi static void
arc4_init(uint8_t * buf,size_t n)57*9d12795fSRobert Mustacchi arc4_init(uint8_t *buf, size_t n)
58*9d12795fSRobert Mustacchi {
59*9d12795fSRobert Mustacchi 	if (n < ARC4_KEYSZ + ARC4_IVSZ)
60*9d12795fSRobert Mustacchi 		abort();
61*9d12795fSRobert Mustacchi 
62*9d12795fSRobert Mustacchi 	chacha_keysetup(&arc4->arc4_chacha, buf, ARC4_KEYSZ * 8, 0);
63*9d12795fSRobert Mustacchi 	chacha_ivsetup(&arc4->arc4_chacha, buf + ARC4_KEYSZ);
64*9d12795fSRobert Mustacchi }
65*9d12795fSRobert Mustacchi 
66*9d12795fSRobert Mustacchi static void
arc4_rekey(uint8_t * data,size_t datalen)67*9d12795fSRobert Mustacchi arc4_rekey(uint8_t *data, size_t datalen)
68*9d12795fSRobert Mustacchi {
69*9d12795fSRobert Mustacchi 	/* Fill in the keystream buffer */
70*9d12795fSRobert Mustacchi 	chacha_encrypt_bytes(&arc4->arc4_chacha, arc4->arc4_buf, arc4->arc4_buf,
71*9d12795fSRobert Mustacchi 	    sizeof (arc4->arc4_buf));
72*9d12795fSRobert Mustacchi 
73*9d12795fSRobert Mustacchi 	/* mix in optional user provided data */
74*9d12795fSRobert Mustacchi 	if (data != NULL) {
75*9d12795fSRobert Mustacchi 		size_t i, m;
76*9d12795fSRobert Mustacchi 
77*9d12795fSRobert Mustacchi 		m = MIN(datalen, ARC4_KEYSZ + ARC4_IVSZ);
78*9d12795fSRobert Mustacchi 		for (i = 0; i < m; i++)
79*9d12795fSRobert Mustacchi 			arc4->arc4_buf[i] ^= data[i];
80*9d12795fSRobert Mustacchi 	}
81*9d12795fSRobert Mustacchi 
82*9d12795fSRobert Mustacchi 	/* immediately reinit for backtracking resistence */
83*9d12795fSRobert Mustacchi 	arc4_init(arc4->arc4_buf, ARC4_KEYSZ + ARC4_IVSZ);
84*9d12795fSRobert Mustacchi 	explicit_bzero(arc4->arc4_buf, ARC4_KEYSZ + ARC4_IVSZ);
85*9d12795fSRobert Mustacchi 	arc4->arc4_have = sizeof (arc4->arc4_buf) - ARC4_KEYSZ - ARC4_IVSZ;
86*9d12795fSRobert Mustacchi }
87*9d12795fSRobert Mustacchi 
88*9d12795fSRobert Mustacchi static void
arc4_stir(size_t len)89*9d12795fSRobert Mustacchi arc4_stir(size_t len)
90*9d12795fSRobert Mustacchi {
91*9d12795fSRobert Mustacchi 	uint8_t rnd[ARC4_KEYSZ + ARC4_IVSZ];
92*9d12795fSRobert Mustacchi 
93*9d12795fSRobert Mustacchi 	if (arc4->arc4_count <= len) {
94*9d12795fSRobert Mustacchi 		if (getentropy(rnd, sizeof (rnd)) == -1)
95*9d12795fSRobert Mustacchi 			abort();
96*9d12795fSRobert Mustacchi 
97*9d12795fSRobert Mustacchi 		if (arc4->arc4_init == B_FALSE) {
98*9d12795fSRobert Mustacchi 			arc4_init(rnd, sizeof (rnd));
99*9d12795fSRobert Mustacchi 			arc4->arc4_init = B_TRUE;
100*9d12795fSRobert Mustacchi 		} else {
101*9d12795fSRobert Mustacchi 			arc4_rekey(rnd, sizeof (rnd));
102*9d12795fSRobert Mustacchi 		}
103*9d12795fSRobert Mustacchi 		explicit_bzero(rnd, sizeof (rnd));
104*9d12795fSRobert Mustacchi 
105*9d12795fSRobert Mustacchi 		/* Invalidate the data buffer */
106*9d12795fSRobert Mustacchi 		arc4->arc4_have = 0;
107*9d12795fSRobert Mustacchi 		memset(arc4->arc4_buf, 0, sizeof (arc4->arc4_buf));
108*9d12795fSRobert Mustacchi 		arc4->arc4_count = ARC4_COUNT;
109*9d12795fSRobert Mustacchi 	}
110*9d12795fSRobert Mustacchi 
111*9d12795fSRobert Mustacchi 	if (arc4->arc4_count <= len) {
112*9d12795fSRobert Mustacchi 		arc4->arc4_count = 0;
113*9d12795fSRobert Mustacchi 	} else {
114*9d12795fSRobert Mustacchi 		arc4->arc4_count -= len;
115*9d12795fSRobert Mustacchi 	}
116*9d12795fSRobert Mustacchi }
117*9d12795fSRobert Mustacchi 
118*9d12795fSRobert Mustacchi static void
arc4_fill(uint8_t * buf,size_t n)119*9d12795fSRobert Mustacchi arc4_fill(uint8_t *buf, size_t n)
120*9d12795fSRobert Mustacchi {
121*9d12795fSRobert Mustacchi 	if (arc4 == NULL) {
122*9d12795fSRobert Mustacchi 		size_t pgsz, mapsz;
123*9d12795fSRobert Mustacchi 		void *a;
124*9d12795fSRobert Mustacchi 
125*9d12795fSRobert Mustacchi 		pgsz = sysconf(_SC_PAGESIZE);
126*9d12795fSRobert Mustacchi 		if (pgsz == -1)
127*9d12795fSRobert Mustacchi 			abort();
128*9d12795fSRobert Mustacchi 		mapsz = P2ROUNDUP(sizeof (arc4_state_t), pgsz);
129*9d12795fSRobert Mustacchi 		a = mmap(NULL, mapsz, PROT_READ | PROT_WRITE,
130*9d12795fSRobert Mustacchi 		    MAP_PRIVATE | MAP_ANON, -1, 0);
131*9d12795fSRobert Mustacchi 		if (a == MAP_FAILED)
132*9d12795fSRobert Mustacchi 			abort();
133*9d12795fSRobert Mustacchi 		if (memcntl(a, mapsz, MC_INHERIT_ZERO, 0, 0, 0) != 0)
134*9d12795fSRobert Mustacchi 			abort();
135*9d12795fSRobert Mustacchi 		arc4 = a;
136*9d12795fSRobert Mustacchi 	}
137*9d12795fSRobert Mustacchi 
138*9d12795fSRobert Mustacchi 	arc4_stir(n);
139*9d12795fSRobert Mustacchi 	while (n > 0) {
140*9d12795fSRobert Mustacchi 		if (arc4->arc4_have > 0) {
141*9d12795fSRobert Mustacchi 			uint8_t *keystream;
142*9d12795fSRobert Mustacchi 			size_t m = MIN(n, arc4->arc4_have);
143*9d12795fSRobert Mustacchi 
144*9d12795fSRobert Mustacchi 			keystream = arc4->arc4_buf + sizeof (arc4->arc4_buf) -
145*9d12795fSRobert Mustacchi 			    arc4->arc4_have;
146*9d12795fSRobert Mustacchi 			memcpy(buf, keystream, m);
147*9d12795fSRobert Mustacchi 			explicit_bzero(keystream, m);
148*9d12795fSRobert Mustacchi 			buf += m;
149*9d12795fSRobert Mustacchi 			n -= m;
150*9d12795fSRobert Mustacchi 			arc4->arc4_have -= m;
151*9d12795fSRobert Mustacchi 		}
152*9d12795fSRobert Mustacchi 		if (arc4->arc4_have == 0)
153*9d12795fSRobert Mustacchi 			arc4_rekey(NULL, 0);
154*9d12795fSRobert Mustacchi 	}
155*9d12795fSRobert Mustacchi }
156*9d12795fSRobert Mustacchi 
157*9d12795fSRobert Mustacchi uint32_t
arc4random(void)158*9d12795fSRobert Mustacchi arc4random(void)
159*9d12795fSRobert Mustacchi {
160*9d12795fSRobert Mustacchi 	uint32_t out;
161*9d12795fSRobert Mustacchi 
162*9d12795fSRobert Mustacchi 	lmutex_lock(&arc4_lock);
163*9d12795fSRobert Mustacchi 	arc4_fill((uint8_t *)&out, sizeof (uint32_t));
164*9d12795fSRobert Mustacchi 	lmutex_unlock(&arc4_lock);
165*9d12795fSRobert Mustacchi 	return (out);
166*9d12795fSRobert Mustacchi }
167*9d12795fSRobert Mustacchi 
168*9d12795fSRobert Mustacchi void
arc4random_buf(void * buf,size_t n)169*9d12795fSRobert Mustacchi arc4random_buf(void *buf, size_t n)
170*9d12795fSRobert Mustacchi {
171*9d12795fSRobert Mustacchi 	lmutex_lock(&arc4_lock);
172*9d12795fSRobert Mustacchi 	arc4_fill(buf, n);
173*9d12795fSRobert Mustacchi 	lmutex_unlock(&arc4_lock);
174*9d12795fSRobert Mustacchi }
175