1/* srm */
2/* Copyright (c) 2000 Matthew D. Gauthier
3 * Portions copyright (c) 2007 Apple Inc.  All rights reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Except as contained in this notice, the name of the contributors shall
25 * not be used in advertising or otherwise to promote the sale, use or
26 * other dealings in this Software without prior written authorization.
27 */
28
29#include <fcntl.h>
30#include <stdlib.h>
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <sys/time.h>
34#include <unistd.h>
35
36#include "removefile.h"
37#include "removefile_priv.h"
38
39static void
40seed_random(removefile_state_t state) {
41#ifdef USE_ARC4RANDOM
42  arc4random_stir();
43#else
44  unsigned int rseed;
45  struct timeval tv;
46  struct timezone tz;
47
48  if (state->urand_file != -1) {
49    read(state->urand_file, &rseed, sizeof(rseed));
50  } else {
51    rseed = rand();
52  }
53  (void)gettimeofday(&tv, &tz);
54  rseed ^= tv.tv_sec + tv.tv_usec + getpid();
55  srand(rseed);
56#endif
57}
58
59void
60__removefile_init_random(const unsigned int seed, removefile_state_t state) {
61#ifdef USE_ARC4RANDOM
62  arc4random_addrandom((unsigned char *)&seed, sizeof(seed));
63#else
64  struct stat statbuf;
65
66  if (stat("/dev/urandom", &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
67    state->urand_file = open("/dev/urandom", O_RDONLY);
68  } else {
69    srand(seed);
70  }
71  seed_random(state);
72#endif
73}
74
75char
76__removefile_random_char(removefile_state_t state) {
77#ifdef USE_ARC4RANDOM
78  random_bytes_read += 4;
79  return arc4random();
80#else
81  char buf[4];
82
83  if (state->urand_file != -1) {
84    read(state->urand_file, &buf, 1);
85    return buf[0];
86  }
87  return rand();
88#endif
89}
90
91void
92__removefile_randomize_buffer(unsigned char *buffer, size_t length, removefile_state_t state) {
93  size_t i;
94
95#ifdef USE_ARC4RANDOM
96  u_int32_t *p = (u_int32_t *)buffer;
97  u_int32_t mod4length = length - (length % 4);
98
99  for (i = 0; i < mod4length; i += 4) {
100    *p++ = arc4random();
101  }
102
103  while (i < length) {
104    buffer[i++] = arc4random();
105  }
106  state->random_bytes_read += (mod4length + ((length - mod4length) * 4));
107  if (state->random_bytes_read > 512*1024*1024 /* RESEED_BYTES */) {
108    state->random_bytes_read = 0;
109    seed_random(state);
110  }
111#else
112  if (state->urand_file != -1) {
113    read(state->urand_file, buffer, length);
114  } else {
115    for (i = 0; i < length; i++)
116      buffer[i] = rand();
117  }
118#endif
119}
120