diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2006-08-08 22:19:39 +0000 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2006-08-08 22:19:39 +0000 |
commit | 65533e1b0939bba6a1a222ebc82189f448640ea9 (patch) | |
tree | f212268d42827ddf7444faf8edc87de3b263fb86 | |
parent | 129e7756b94ed951e74bb2fb062e45a9f718224c (diff) | |
download | coreutils-65533e1b0939bba6a1a222ebc82189f448640ea9.tar.xz |
Use new random-number interface rather than rand-isaac.c.
Don't include rand-isaac.c; include randint.h and randread.h instead.
(RANDOM_SOURCE_OPTION): New enum.
(long_opts, usage, main): New option --random-source.
(struct irand_state, irand_init, irand32, irand_mod): Remove.
All callers changed to use randint interface.
(fillrand): Remove. All callers changed to use randread interface.
(dopass): Remove dependency on ISAAC buffer size.
(genpattern): Don't wipe the random state here.
(randint_source): New static var.
(clear_random_data): New function.
(main): Allocate random source, and arrange to wipe it on exit.
-rw-r--r-- | src/shred.c | 158 |
1 files changed, 53 insertions, 105 deletions
diff --git a/src/shred.c b/src/shred.c index e61b2d16a..8d5c0c7fa 100644 --- a/src/shred.c +++ b/src/shred.c @@ -60,9 +60,6 @@ * If asked to wipe a file, this also unlinks it, renaming it to in a * clever way to try to leave no trace of the original filename. * - * The ISAAC code still bears some resemblance to the code written - * by Bob Jenkins, but he permits pretty unlimited use. - * * This was inspired by a desire to improve on some code titled: * Wipe V1.0-- Overwrite and delete files. S. 2/3/96 * but I've rewritten everything here so completely that no trace of @@ -108,8 +105,8 @@ #include "inttostr.h" #include "quotearg.h" /* For quotearg_colon */ #include "quote.h" /* For quotearg_colon */ - -#include "rand-isaac.c" +#include "randint.h" +#include "randread.h" #define DEFAULT_PASSES 25 /* Default */ @@ -128,12 +125,20 @@ struct Options bool zero_fill; /* -z flag: Add a final zero pass */ }; +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + RANDOM_SOURCE_OPTION = CHAR_MAX + 1 +}; + static struct option const long_opts[] = { {"exact", no_argument, NULL, 'x'}, {"force", no_argument, NULL, 'f'}, {"iterations", required_argument, NULL, 'n'}, {"size", required_argument, NULL, 's'}, + {"random-source", required_argument, NULL, RANDOM_SOURCE_OPTION}, {"remove", no_argument, NULL, 'u'}, {"verbose", no_argument, NULL, 'v'}, {"zero", no_argument, NULL, 'z'}, @@ -165,6 +170,7 @@ Mandatory arguments to long options are mandatory for short options too.\n\ printf (_("\ -f, --force change permissions to allow writing if necessary\n\ -n, --iterations=N Overwrite N times instead of the default (%d)\n\ + --random-source=FILE get random bytes from FILE (default /dev/urandom)\n\ -s, --size=N shred this many bytes (suffixes like K, M, G accepted)\n\ "), DEFAULT_PASSES); fputs (_("\ @@ -227,65 +233,6 @@ to be recovered later.\n\ exit (status); } -/* Single-word RNG built on top of ISAAC */ -struct irand_state -{ - uint32_t r[ISAAC_WORDS]; - unsigned int numleft; - struct isaac_state *s; -}; - -static void -irand_init (struct irand_state *r, struct isaac_state *s) -{ - r->numleft = 0; - r->s = s; -} - -/* - * We take from the end of the block deliberately, so if we need - * only a small number of values, we choose the final ones which are - * marginally better mixed than the initial ones. - */ -static uint32_t -irand32 (struct irand_state *r) -{ - if (!r->numleft) - { - isaac_refill (r->s, r->r); - r->numleft = ISAAC_WORDS; - } - return r->r[--r->numleft]; -} - -/* - * Return a uniformly distributed random number between 0 and n, - * inclusive. Thus, the result is modulo n+1. - * - * Theory of operation: as x steps through every possible 32-bit number, - * x % n takes each value at least 2^32 / n times (rounded down), but - * the values less than 2^32 % n are taken one additional time. Thus, - * x % n is not perfectly uniform. To fix this, the values of x less - * than 2^32 % n are disallowed, and if the RNG produces one, we ask - * for a new value. - */ -static uint32_t -irand_mod (struct irand_state *r, uint32_t n) -{ - uint32_t x; - uint32_t lim; - - if (!++n) - return irand32 (r); - - lim = -n % n; /* == (2**32-n) % n == 2**32 % n */ - do - { - x = irand32 (r); - } - while (x < lim); - return x % n; -} /* * Fill a buffer with a fixed pattern. @@ -315,23 +262,6 @@ fillpattern (int type, unsigned char *r, size_t size) } /* - * Fill a buffer, R (of size SIZE_MAX), with random data. - * SIZE is rounded UP to a multiple of ISAAC_BYTES. - */ -static void -fillrand (struct isaac_state *s, uint32_t *r, size_t size_max, size_t size) -{ - size_t refills = (size + ISAAC_BYTES - 1) / ISAAC_BYTES; - assert (refills * ISAAC_BYTES <= size_max); - - while (refills--) - { - isaac_refill (s, r); - r += ISAAC_WORDS; - } -} - -/* * Generate a 6-character (+ nul) pass name string * FIXME: allow translation of "random". */ @@ -419,7 +349,7 @@ direct_mode (int fd, bool enable) */ static int dopass (int fd, char const *qname, off_t *sizep, int type, - struct isaac_state *s, unsigned long int k, unsigned long int n) + struct randread_source *s, unsigned long int k, unsigned long int n) { off_t size = *sizep; off_t offset; /* Current file posiiton */ @@ -428,7 +358,7 @@ dopass (int fd, char const *qname, off_t *sizep, int type, size_t lim; /* Amount of data to try writing */ size_t soff; /* Offset into buffer for next write */ ssize_t ssize; /* Return value from write */ - uint32_t r[3 * MAX (ISAAC_WORDS, 1024)]; /* Fill pattern. */ + uint32_t r[3 * 1024]; /* Fill pattern. */ char pass_string[PASS_NAME_SIZE]; /* Name of current pass */ bool write_error = false; bool first_write = true; @@ -481,7 +411,7 @@ dopass (int fd, char const *qname, off_t *sizep, int type, break; } if (type < 0) - fillrand (s, r, sizeof r, lim); + randread (s, r, lim); /* Loop to retry partial writes. */ for (soff = 0; soff < lim; soff += ssize, first_write = false) { @@ -700,9 +630,8 @@ static int const * order. */ static void -genpattern (int *dest, size_t num, struct isaac_state *s) +genpattern (int *dest, size_t num, struct randint_source *s) { - struct irand_state r; size_t randpasses; int const *p; int *d; @@ -713,8 +642,6 @@ genpattern (int *dest, size_t num, struct isaac_state *s) if (!num) return; - irand_init (&r, s); - /* Stage 1: choose the passes to use */ p = patterns; randpasses = 0; @@ -756,7 +683,7 @@ genpattern (int *dest, size_t num, struct isaac_state *s) { /* Pad out with k of the n available */ do { - if (n == (size_t) k-- || irand_mod (&r, k) < n) + if (n == (size_t) k || randint_choose (s, k) < n) { *d++ = *p; n--; @@ -802,7 +729,7 @@ genpattern (int *dest, size_t num, struct isaac_state *s) } else { - swap = n + irand_mod (&r, top - n - 1); + swap = n + randint_choose (s, top - n); k = dest[n]; dest[n] = dest[swap]; dest[swap] = k; @@ -810,8 +737,6 @@ genpattern (int *dest, size_t num, struct isaac_state *s) accum -= randpasses; } /* assert (top == num); */ - - memset (&r, 0, sizeof r); /* Wipe this on general principles */ } /* @@ -819,7 +744,7 @@ genpattern (int *dest, size_t num, struct isaac_state *s) * size bytes of the given fd. Return true if successful. */ static bool -do_wipefd (int fd, char const *qname, struct isaac_state *s, +do_wipefd (int fd, char const *qname, struct randint_source *s, struct Options const *flags) { size_t i; @@ -828,6 +753,7 @@ do_wipefd (int fd, char const *qname, struct isaac_state *s, unsigned long int n; /* Number of passes for printing purposes */ int *passarray; bool ok = true; + struct randread_source *rs; n = 0; /* dopass takes n -- 0 to mean "don't print progress" */ if (flags->verbose) @@ -894,10 +820,12 @@ do_wipefd (int fd, char const *qname, struct isaac_state *s, /* Schedule the passes in random order. */ genpattern (passarray, flags->n_iterations, s); + rs = randint_get_source (s); + /* Do the work */ for (i = 0; i < flags->n_iterations; i++) { - int err = dopass (fd, qname, &size, passarray[i], s, i + 1, n); + int err = dopass (fd, qname, &size, passarray[i], rs, i + 1, n); if (err) { if (err < 0) @@ -915,7 +843,7 @@ do_wipefd (int fd, char const *qname, struct isaac_state *s, if (flags->zero_fill) { - int err = dopass (fd, qname, &size, 0, s, flags->n_iterations + 1, n); + int err = dopass (fd, qname, &size, 0, rs, flags->n_iterations + 1, n); if (err) { if (err < 0) @@ -939,7 +867,7 @@ do_wipefd (int fd, char const *qname, struct isaac_state *s, /* A wrapper with a little more checking for fds on the command line */ static bool -wipefd (int fd, char const *qname, struct isaac_state *s, +wipefd (int fd, char const *qname, struct randint_source *s, struct Options const *flags) { int fd_flags = fcntl (fd, F_GETFL); @@ -1110,7 +1038,7 @@ wipename (char *oldname, char const *qoldname, struct Options const *flags) */ static bool wipefile (char *name, char const *qname, - struct isaac_state *s, struct Options const *flags) + struct randint_source *s, struct Options const *flags) { bool ok; int fd; @@ -1137,16 +1065,30 @@ wipefile (char *name, char const *qname, return ok; } + +/* Buffers for random data. */ +static struct randint_source *randint_source; + +/* Just on general principles, wipe buffers containing information + that may be related to the possibly-pseudorandom values used during + shredding. */ +static void +clear_random_data (void) +{ + randint_all_free (randint_source); +} + + int main (int argc, char **argv) { - struct isaac_state s; bool ok = true; struct Options flags; char **file; int n_files; int c; int i; + char const *random_source = NULL; initialize_main (&argc, &argv); program_name = argv[0]; @@ -1156,8 +1098,6 @@ main (int argc, char **argv) atexit (close_stdout); - isaac_seed (&s); - memset (&flags, 0, sizeof flags); flags.n_iterations = DEFAULT_PASSES; @@ -1185,6 +1125,12 @@ main (int argc, char **argv) } break; + case RANDOM_SOURCE_OPTION: + if (random_source && !STREQ (random_source, optarg)) + error (EXIT_FAILURE, 0, _("multiple random sources specified")); + random_source = optarg; + break; + case 'u': flags.remove_file = true; break; @@ -1232,24 +1178,26 @@ main (int argc, char **argv) usage (EXIT_FAILURE); } + randint_source = randint_all_new (random_source, SIZE_MAX); + if (! randint_source) + error (EXIT_FAILURE, errno, "%s", quotearg_colon (random_source)); + atexit (clear_random_data); + for (i = 0; i < n_files; i++) { char *qname = xstrdup (quotearg_colon (file[i])); if (STREQ (file[i], "-")) { - ok &= wipefd (STDOUT_FILENO, qname, &s, &flags); + ok &= wipefd (STDOUT_FILENO, qname, randint_source, &flags); } else { /* Plain filename - Note that this overwrites *argv! */ - ok &= wipefile (file[i], qname, &s, &flags); + ok &= wipefile (file[i], qname, randint_source, &flags); } free (qname); } - /* Just on general principles, wipe s. */ - memset (&s, 0, sizeof s); - exit (ok ? EXIT_SUCCESS : EXIT_FAILURE); } /* |