1 /* $OpenBSD: arc4random.c,v 1.53 2015/09/10 18:53:50 bcook 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)
52 /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
54 size_t rs_have
; /* valid bytes at end of rs_buf */
55 size_t rs_count
; /* bytes till reseed */
58 /* Maybe be preserved in fork children, if _rs_allocate() decides. */
60 chacha_ctx rs_chacha
; /* chacha context for random keystream */
61 u_char rs_buf
[RSBUFSZ
]; /* keystream blocks */
64 static inline int _rs_allocate(struct _rs
**, struct _rsx
**);
65 static inline void _rs_forkdetect(void);
66 #include "arc4random.h"
68 static inline void _rs_rekey(u_char
*dat
, size_t datlen
);
71 _rs_init(u_char
*buf
, size_t n
)
77 if (_rs_allocate(&rs
, &rsx
) == -1)
81 chacha_keysetup(&rsx
->rs_chacha
, buf
, KEYSZ
* 8, 0);
82 chacha_ivsetup(&rsx
->rs_chacha
, buf
+ KEYSZ
);
88 u_char rnd
[KEYSZ
+ IVSZ
];
90 if (getentropy(rnd
, sizeof rnd
) == -1)
94 _rs_init(rnd
, sizeof(rnd
));
96 _rs_rekey(rnd
, sizeof(rnd
));
97 explicit_bzero(rnd
, sizeof(rnd
)); /* discard source seed */
99 /* invalidate rs_buf */
101 memset(rsx
->rs_buf
, 0, sizeof(rsx
->rs_buf
));
103 rs
->rs_count
= 1600000;
107 _rs_stir_if_needed(size_t len
)
110 if (!rs
|| rs
->rs_count
<= len
)
112 if (rs
->rs_count
<= len
)
119 _rs_rekey(u_char
*dat
, size_t datlen
)
121 #ifndef KEYSTREAM_ONLY
122 memset(rsx
->rs_buf
, 0, sizeof(rsx
->rs_buf
));
124 /* fill rs_buf with the keystream */
125 chacha_encrypt_bytes(&rsx
->rs_chacha
, rsx
->rs_buf
,
126 rsx
->rs_buf
, sizeof(rsx
->rs_buf
));
127 /* mix in optional user provided data */
131 m
= minimum(datlen
, KEYSZ
+ IVSZ
);
132 for (i
= 0; i
< m
; i
++)
133 rsx
->rs_buf
[i
] ^= dat
[i
];
135 /* immediately reinit for backtracking resistance */
136 _rs_init(rsx
->rs_buf
, KEYSZ
+ IVSZ
);
137 memset(rsx
->rs_buf
, 0, KEYSZ
+ IVSZ
);
138 rs
->rs_have
= sizeof(rsx
->rs_buf
) - KEYSZ
- IVSZ
;
142 _rs_random_buf(void *_buf
, size_t n
)
144 u_char
*buf
= (u_char
*)_buf
;
148 _rs_stir_if_needed(n
);
150 if (rs
->rs_have
> 0) {
151 m
= minimum(n
, rs
->rs_have
);
152 keystream
= rsx
->rs_buf
+ sizeof(rsx
->rs_buf
)
154 memcpy(buf
, keystream
, m
);
155 memset(keystream
, 0, m
);
160 if (rs
->rs_have
== 0)
166 _rs_random_u32(uint32_t *val
)
170 _rs_stir_if_needed(sizeof(*val
));
171 if (rs
->rs_have
< sizeof(*val
))
173 keystream
= rsx
->rs_buf
+ sizeof(rsx
->rs_buf
) - rs
->rs_have
;
174 memcpy(val
, keystream
, sizeof(*val
));
175 memset(keystream
, 0, sizeof(*val
));
176 rs
->rs_have
-= sizeof(*val
);
185 _rs_random_u32(&val
);
191 arc4random_buf(void *buf
, size_t n
)
194 _rs_random_buf(buf
, n
);