1 /* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */
4 * Copyright (c) 1996, David Mazieres <dm@uun.org>
5 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
6 * Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
7 * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * ChaCha based random number generator for OpenBSD.
33 #include <sys/types.h>
36 #define KEYSTREAM_ONLY
37 #include "chacha_private.h"
39 #define minimum(a, b) ((a) < (b) ? (a) : (b))
41 #if defined(__GNUC__) || defined(_MSC_VER)
42 #define inline __inline
43 #else /* __GNUC__ || _MSC_VER */
45 #endif /* !__GNUC__ && !_MSC_VER */
50 #define RSBUFSZ (16*BLOCKSZ)
53 #define REKEY_BASE ( 32*1024) /* NB. should be a power of 2 */
54 #elif SIZE_MAX <= 1048575
55 #define REKEY_BASE ( 512*1024) /* NB. should be a power of 2 */
57 #define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
60 /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
62 size_t rs_have
; /* valid bytes at end of rs_buf */
63 size_t rs_count
; /* bytes till reseed */
66 /* Maybe be preserved in fork children, if _rs_allocate() decides. */
68 chacha_ctx rs_chacha
; /* chacha context for random keystream */
69 u_char rs_buf
[RSBUFSZ
]; /* keystream blocks */
72 static inline int _rs_allocate(struct _rs
**, struct _rsx
**);
73 static inline void _rs_forkdetect(void);
74 #include "arc4random.h"
76 static inline void _rs_rekey(u_char
*dat
, size_t datlen
);
79 _rs_init(u_char
*buf
, size_t n
)
85 if (_rs_allocate(&rs
, &rsx
) == -1)
89 chacha_keysetup(&rsx
->rs_chacha
, buf
, KEYSZ
* 8);
90 chacha_ivsetup(&rsx
->rs_chacha
, buf
+ KEYSZ
);
96 u_char rnd
[KEYSZ
+ IVSZ
];
97 uint32_t rekey_fuzz
= 0;
99 memset(rnd
, 0, (KEYSZ
+ IVSZ
) * sizeof(u_char
));
101 if (getentropy(rnd
, sizeof rnd
) == -1)
105 _rs_init(rnd
, sizeof(rnd
));
107 _rs_rekey(rnd
, sizeof(rnd
));
108 explicit_bzero(rnd
, sizeof(rnd
)); /* discard source seed */
110 /* invalidate rs_buf */
112 memset(rsx
->rs_buf
, 0, sizeof(rsx
->rs_buf
));
114 /* rekey interval should not be predictable */
115 chacha_encrypt_bytes(&rsx
->rs_chacha
, (uint8_t *)&rekey_fuzz
,
116 (uint8_t *)&rekey_fuzz
, sizeof(rekey_fuzz
));
117 rs
->rs_count
= REKEY_BASE
+ (rekey_fuzz
% REKEY_BASE
);
121 _rs_stir_if_needed(size_t len
)
124 if (!rs
|| rs
->rs_count
<= len
)
126 if (rs
->rs_count
<= len
)
133 _rs_rekey(u_char
*dat
, size_t datlen
)
135 #ifndef KEYSTREAM_ONLY
136 memset(rsx
->rs_buf
, 0, sizeof(rsx
->rs_buf
));
138 /* fill rs_buf with the keystream */
139 chacha_encrypt_bytes(&rsx
->rs_chacha
, rsx
->rs_buf
,
140 rsx
->rs_buf
, sizeof(rsx
->rs_buf
));
141 /* mix in optional user provided data */
145 m
= minimum(datlen
, KEYSZ
+ IVSZ
);
146 for (i
= 0; i
< m
; i
++)
147 rsx
->rs_buf
[i
] ^= dat
[i
];
149 /* immediately reinit for backtracking resistance */
150 _rs_init(rsx
->rs_buf
, KEYSZ
+ IVSZ
);
151 memset(rsx
->rs_buf
, 0, KEYSZ
+ IVSZ
);
152 rs
->rs_have
= sizeof(rsx
->rs_buf
) - KEYSZ
- IVSZ
;
156 _rs_random_buf(void *_buf
, size_t n
)
158 u_char
*buf
= (u_char
*)_buf
;
162 _rs_stir_if_needed(n
);
164 if (rs
->rs_have
> 0) {
165 m
= minimum(n
, rs
->rs_have
);
166 keystream
= rsx
->rs_buf
+ sizeof(rsx
->rs_buf
)
168 memcpy(buf
, keystream
, m
);
169 memset(keystream
, 0, m
);
174 if (rs
->rs_have
== 0)
180 _rs_random_u32(uint32_t *val
)
184 _rs_stir_if_needed(sizeof(*val
));
185 if (rs
->rs_have
< sizeof(*val
))
187 keystream
= rsx
->rs_buf
+ sizeof(rsx
->rs_buf
) - rs
->rs_have
;
188 memcpy(val
, keystream
, sizeof(*val
));
189 memset(keystream
, 0, sizeof(*val
));
190 rs
->rs_have
-= sizeof(*val
);
198 #ifndef __SINGLE_THREAD__
201 _rs_random_u32(&val
);
202 #ifndef __SINGLE_THREAD__
209 arc4random_buf(void *buf
, size_t n
)
211 #ifndef __SINGLE_THREAD__
214 _rs_random_buf(buf
, n
);
215 #ifndef __SINGLE_THREAD__