passman

dead simple password manager using state of the art encryption
git clone git://kqueue.dev/passman.git
Log | Files | Refs | README | LICENSE

arc4random.c (4708B)


      1 /*	$OpenBSD: arc4random.c,v 1.54 2015/09/13 08:31:47 guenther Exp $	*/
      2 
      3 /*
      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>
      8  *
      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.
     12  *
     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.
     20  */
     21 
     22 /*
     23  * ChaCha based random number generator for OpenBSD.
     24  */
     25 
     26 #include <fcntl.h>
     27 #include <limits.h>
     28 #include <signal.h>
     29 #include <stdint.h>
     30 #include <stdlib.h>
     31 #include <string.h>
     32 #include <unistd.h>
     33 #include <sys/types.h>
     34 #include <sys/time.h>
     35 
     36 #define KEYSTREAM_ONLY
     37 #include "chacha_private.h"
     38 
     39 #define minimum(a, b) ((a) < (b) ? (a) : (b))
     40 
     41 #if defined(__GNUC__) || defined(_MSC_VER)
     42 #define inline __inline
     43 #else				/* __GNUC__ || _MSC_VER */
     44 #define inline
     45 #endif				/* !__GNUC__ && !_MSC_VER */
     46 
     47 #define KEYSZ	32
     48 #define IVSZ	8
     49 #define BLOCKSZ	64
     50 #define RSBUFSZ	(16*BLOCKSZ)
     51 
     52 /* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
     53 static struct _rs {
     54 	size_t		rs_have;	/* valid bytes at end of rs_buf */
     55 	size_t		rs_count;	/* bytes till reseed */
     56 } *rs;
     57 
     58 /* Maybe be preserved in fork children, if _rs_allocate() decides. */
     59 static struct _rsx {
     60 	chacha_ctx	rs_chacha;	/* chacha context for random keystream */
     61 	u_char		rs_buf[RSBUFSZ];	/* keystream blocks */
     62 } *rsx;
     63 
     64 static inline int _rs_allocate(struct _rs **, struct _rsx **);
     65 static inline void _rs_forkdetect(void);
     66 #include "arc4random.h"
     67 
     68 static inline void _rs_rekey(u_char *dat, size_t datlen);
     69 
     70 static inline void
     71 _rs_init(u_char *buf, size_t n)
     72 {
     73 	if (n < KEYSZ + IVSZ)
     74 		return;
     75 
     76 	if (rs == NULL) {
     77 		if (_rs_allocate(&rs, &rsx) == -1)
     78 			abort();
     79 	}
     80 
     81 	chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8, 0);
     82 	chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ);
     83 }
     84 
     85 static void
     86 _rs_stir(void)
     87 {
     88 	u_char rnd[KEYSZ + IVSZ];
     89 
     90 	if (getentropy(rnd, sizeof rnd) == -1)
     91 		_getentropy_fail();
     92 
     93 	if (!rs)
     94 		_rs_init(rnd, sizeof(rnd));
     95 	else
     96 		_rs_rekey(rnd, sizeof(rnd));
     97 	explicit_bzero(rnd, sizeof(rnd));	/* discard source seed */
     98 
     99 	/* invalidate rs_buf */
    100 	rs->rs_have = 0;
    101 	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
    102 
    103 	rs->rs_count = 1600000;
    104 }
    105 
    106 static inline void
    107 _rs_stir_if_needed(size_t len)
    108 {
    109 	_rs_forkdetect();
    110 	if (!rs || rs->rs_count <= len)
    111 		_rs_stir();
    112 	if (rs->rs_count <= len)
    113 		rs->rs_count = 0;
    114 	else
    115 		rs->rs_count -= len;
    116 }
    117 
    118 static inline void
    119 _rs_rekey(u_char *dat, size_t datlen)
    120 {
    121 #ifndef KEYSTREAM_ONLY
    122 	memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
    123 #endif
    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 */
    128 	if (dat) {
    129 		size_t i, m;
    130 
    131 		m = minimum(datlen, KEYSZ + IVSZ);
    132 		for (i = 0; i < m; i++)
    133 			rsx->rs_buf[i] ^= dat[i];
    134 	}
    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;
    139 }
    140 
    141 static inline void
    142 _rs_random_buf(void *_buf, size_t n)
    143 {
    144 	u_char *buf = (u_char *)_buf;
    145 	u_char *keystream;
    146 	size_t m;
    147 
    148 	_rs_stir_if_needed(n);
    149 	while (n > 0) {
    150 		if (rs->rs_have > 0) {
    151 			m = minimum(n, rs->rs_have);
    152 			keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
    153 			    - rs->rs_have;
    154 			memcpy(buf, keystream, m);
    155 			memset(keystream, 0, m);
    156 			buf += m;
    157 			n -= m;
    158 			rs->rs_have -= m;
    159 		}
    160 		if (rs->rs_have == 0)
    161 			_rs_rekey(NULL, 0);
    162 	}
    163 }
    164 
    165 static inline void
    166 _rs_random_u32(uint32_t *val)
    167 {
    168 	u_char *keystream;
    169 
    170 	_rs_stir_if_needed(sizeof(*val));
    171 	if (rs->rs_have < sizeof(*val))
    172 		_rs_rekey(NULL, 0);
    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);
    177 }
    178 
    179 uint32_t
    180 arc4random(void)
    181 {
    182 	uint32_t val;
    183 
    184 	_ARC4_LOCK();
    185 	_rs_random_u32(&val);
    186 	_ARC4_UNLOCK();
    187 	return val;
    188 }
    189 //DEF_WEAK(arc4random);
    190 
    191 void
    192 arc4random_buf(void *buf, size_t n)
    193 {
    194 	_ARC4_LOCK();
    195 	_rs_random_buf(buf, n);
    196 	_ARC4_UNLOCK();
    197 }
    198 //DEF_WEAK(arc4random_buf);