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