2 * Copyright (c) 1996, David Mazieres <dm@uun.org>
3 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
4 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
5 * Copyright (c) 2015 Joyent, Inc.
7 * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * arc4random(3C), derived from the OpenBSD version.
23 * To ensure that a parent process and any potential children see a different
24 * state, we mmap the entire arc4_state_t structure and mark that page as
25 * MC_INHERIT_ZERO. That ensures that the data is zeroed, and really the bit we
26 * care about, arc4_init is set to B_FALSE, which will cause the child to
27 * reinitialize it when they first use the interface.
34 #include <sys/sysmacros.h>
37 #include "thr_uberdata.h"
41 #define ARC4_BLOCKSZ 64
42 #define ARC4_KSBUFSZ (16*ARC4_BLOCKSZ) /* key stream byte size */
43 #define ARC4_COUNT 1600000 /* bytes for rekeying */
45 typedef struct arc4_state
{
46 boolean_t arc4_init
; /* Initialized? */
47 size_t arc4_have
; /* Valid bytes in arc4_buf */
48 size_t arc4_count
; /* bytes until reseed */
49 chacha_ctx_t arc4_chacha
; /* chacha context */
50 uint8_t arc4_buf
[ARC4_KSBUFSZ
]; /* keystream blocks */
53 static arc4_state_t
*arc4
;
54 static mutex_t arc4_lock
= DEFAULTMUTEX
;
57 arc4_init(uint8_t *buf
, size_t n
)
59 if (n
< ARC4_KEYSZ
+ ARC4_IVSZ
)
62 chacha_keysetup(&arc4
->arc4_chacha
, buf
, ARC4_KEYSZ
* 8, 0);
63 chacha_ivsetup(&arc4
->arc4_chacha
, buf
+ ARC4_KEYSZ
);
67 arc4_rekey(uint8_t *data
, size_t datalen
)
69 /* Fill in the keystream buffer */
70 chacha_encrypt_bytes(&arc4
->arc4_chacha
, arc4
->arc4_buf
, arc4
->arc4_buf
,
71 sizeof (arc4
->arc4_buf
));
73 /* mix in optional user provided data */
77 m
= MIN(datalen
, ARC4_KEYSZ
+ ARC4_IVSZ
);
78 for (i
= 0; i
< m
; i
++)
79 arc4
->arc4_buf
[i
] ^= data
[i
];
82 /* immediately reinit for backtracking resistence */
83 arc4_init(arc4
->arc4_buf
, ARC4_KEYSZ
+ ARC4_IVSZ
);
84 explicit_bzero(arc4
->arc4_buf
, ARC4_KEYSZ
+ ARC4_IVSZ
);
85 arc4
->arc4_have
= sizeof (arc4
->arc4_buf
) - ARC4_KEYSZ
- ARC4_IVSZ
;
91 uint8_t rnd
[ARC4_KEYSZ
+ ARC4_IVSZ
];
93 if (arc4
->arc4_count
<= len
) {
94 if (getentropy(rnd
, sizeof (rnd
)) == -1)
97 if (arc4
->arc4_init
== B_FALSE
) {
98 arc4_init(rnd
, sizeof (rnd
));
99 arc4
->arc4_init
= B_TRUE
;
101 arc4_rekey(rnd
, sizeof (rnd
));
103 explicit_bzero(rnd
, sizeof (rnd
));
105 /* Invalidate the data buffer */
107 memset(arc4
->arc4_buf
, 0, sizeof (arc4
->arc4_buf
));
108 arc4
->arc4_count
= ARC4_COUNT
;
111 if (arc4
->arc4_count
<= len
) {
112 arc4
->arc4_count
= 0;
114 arc4
->arc4_count
-= len
;
119 arc4_fill(uint8_t *buf
, size_t n
)
125 pgsz
= sysconf(_SC_PAGESIZE
);
128 mapsz
= P2ROUNDUP(sizeof (arc4_state_t
), pgsz
);
129 a
= mmap(NULL
, mapsz
, PROT_READ
| PROT_WRITE
,
130 MAP_PRIVATE
| MAP_ANON
, -1, 0);
133 if (memcntl(a
, mapsz
, MC_INHERIT_ZERO
, 0, 0, 0) != 0)
140 if (arc4
->arc4_have
> 0) {
142 size_t m
= MIN(n
, arc4
->arc4_have
);
144 keystream
= arc4
->arc4_buf
+ sizeof (arc4
->arc4_buf
) -
146 memcpy(buf
, keystream
, m
);
147 explicit_bzero(keystream
, m
);
150 arc4
->arc4_have
-= m
;
152 if (arc4
->arc4_have
== 0)
162 lmutex_lock(&arc4_lock
);
163 arc4_fill((uint8_t *)&out
, sizeof (uint32_t));
164 lmutex_unlock(&arc4_lock
);
169 arc4random_buf(void *buf
, size_t n
)
171 lmutex_lock(&arc4_lock
);
173 lmutex_unlock(&arc4_lock
);