📄 shred.c
字号:
/* shred.c - overwrite files and devices to make it harder to recover data Copyright (C) 1999-2002 Free Software Foundation, Inc. Copyright (C) 1997, 1998, 1999 Colin Plumb. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Written by Colin Plumb. *//* TODO: - use consistent non-capitalization in error messages - add standard GNU copyleft comment - Add -r/-R/--recursive - Add -i/--interactive - Reserve -d - Add -L - Deal with the amazing variety of gettimeofday() implementation bugs. (Some systems use a one-arg form; still others insist that the timezone either be NULL or be non-NULL. Whee.) - Add an unlink-all option to emulate rm. *//* * Do a more secure overwrite of given files or devices, to make it harder * for even very expensive hardware probing to recover the data. * * Although this process is also known as "wiping", I prefer the longer * name both because I think it is more evocative of what is happening and * because a longer name conveys a more appropriate sense of deliberateness. * * For the theory behind this, see "Secure Deletion of Data from Magnetic * and Solid-State Memory", on line at * http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html * * Just for the record, reversing one or two passes of disk overwrite * is not terribly difficult with hardware help. Hook up a good-quality * digitizing oscilloscope to the output of the head preamplifier and copy * the high-res digitized data to a computer for some off-line analysis. * Read the "current" data and average all the pulses together to get an * "average" pulse on the disk. Subtract this average pulse from all of * the actual pulses and you can clearly see the "echo" of the previous * data on the disk. * * Real hard drives have to balance the cost of the media, the head, * and the read circuitry. They use better-quality media than absolutely * necessary to limit the cost of the read circuitry. By throwing that * assumption out, and the assumption that you want the data processed * as fast as the hard drive can spin, you can do better. * * 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 * the original remains. * * Thanks to: * Bob Jenkins, for his good RNG work and patience with the FSF copyright * paperwork. * Jim Meyering, for his work merging this into the GNU fileutils while * still letting me feel a sense of ownership and pride. Getting me to * tolerate the GNU brace style was quite a feat of diplomacy. * Paul Eggert, for lots of useful discussion and code. I disagree with * an awful lot of his suggestions, but they're disagreements worth having. * * Things to think about: * - Security: Is there any risk to the race * between overwriting and unlinking a file? Will it do anything * drastically bad if told to attack a named pipe or socket? *//* The official name of this program (e.g., no `g' prefix). */#define PROGRAM_NAME "shred"#define AUTHORS "Colin Plumb"#if HAVE_CONFIG_H# include <config.h>#endif#include <getopt.h>#include <stdio.h>#include <assert.h>#include <setjmp.h>#include <signal.h>#include <sys/types.h>#include "system.h"#include "xstrtol.h"#include "closeout.h"#include "error.h"#include "human.h"#include "quotearg.h" /* For quotearg_colon */#include "quote.h" /* For quotearg_colon */char *xstrdup PARAMS ((char const *));#ifndef O_NOCTTY# define O_NOCTTY 0 /* This is a very optional frill */#endif/* Some systems don't support some file types. */#ifndef S_ISFIFO# define S_ISFIFO(mode) 0#endif#ifndef S_ISLNK# define S_ISLNK(mode) 0#endif#ifndef S_ISSOCK# define S_ISSOCK(mode) 0#endif#define DEFAULT_PASSES 25 /* Default *//* How many seconds to wait before checking whether to output another verbose output line. */#define VERBOSE_UPDATE 5/* If positive, the units to use when printing sizes; if negative, the human-readable base. */#define OUTPUT_BLOCK_SIZE (-1024)struct Options{ int force; /* -f flag: chmod files if necessary */ size_t n_iterations; /* -n flag: Number of iterations */ off_t size; /* -s flag: size of file */ int remove_file; /* -u flag: remove file after shredding */ int verbose; /* -v flag: Print progress */ int exact; /* -x flag: Do not round up file size */ int zero_fill; /* -z flag: Add a final zero pass */};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'}, {"remove", no_argument, NULL, 'u'}, {"verbose", no_argument, NULL, 'v'}, {"zero", required_argument, NULL, 'z'}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0}};/* Global variable for error printing purposes */char const *program_name; /* Initialized before any possible use */voidusage (int status){ if (status != 0) fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); else { printf (_("Usage: %s [OPTIONS] FILE [...]\n"), program_name); fputs (_("\Overwrite the specified FILE(s) repeatedly, in order to make it harder\n\for even very expensive hardware probing to recover the data.\n\\n\"), stdout); fputs (_("\Mandatory arguments to long options are mandatory for short options too.\n\"), stdout); printf (_("\ -f, --force change permissions to allow writing if necessary\n\ -n, --iterations=N Overwrite N times instead of the default (%d)\n\ -s, --size=N shred this many bytes (suffixes like K, M, G accepted)\n\"), DEFAULT_PASSES); fputs (_("\ -u, --remove truncate and remove file after overwriting\n\ -v, --verbose show progress\n\ -x, --exact do not round file sizes up to the next full block\n\ -z, --zero add a final overwrite with zeros to hide shredding\n\ - shred standard output\n\"), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); fputs (_("\\n\Delete FILE(s) if --remove (-u) is specified. The default is not to remove\n\the files because it is common to operate on device files like /dev/hda,\n\and those files usually should not be removed. When operating on regular\n\files, most people use the --remove option.\n\\n\"), stdout); fputs (_("\CAUTION: Note that shred relies on a very important assumption:\n\that the filesystem overwrites data in place. This is the traditional\n\way to do things, but many modern filesystem designs do not satisfy this\n\assumption. The following are examples of filesystems on which shred is\n\not effective:\n\\n\"), stdout); fputs (_("\* log-structured or journaled filesystems, such as those supplied with\n\ AIX and Solaris (and JFS, ReiserFS, XFS, Ext3, etc.)\n\\n\* filesystems that write redundant data and carry on even if some writes\n\ fail, such as RAID-based filesystems\n\\n\* filesystems that make snapshots, such as Network Appliance's NFS server\n\\n\"), stdout); fputs (_("\* filesystems that cache in temporary locations, such as NFS\n\ version 3 clients\n\\n\* compressed filesystems\n\\n\In addition, file system backups and remote mirrors may contain copies\n\of the file that cannot be removed, and that will allow a shredded file\n\to be recovered later.\n\"), stdout); printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); } exit (status);}#if ! HAVE_FDATASYNC# define fdatasync(fd) -1#endif/* * -------------------------------------------------------------------- * Bob Jenkins' cryptographic random number generator, ISAAC. * Hacked by Colin Plumb. * * We need a source of random numbers for some of the overwrite data. * Cryptographically secure is desirable, but it's not life-or-death * so I can be a little bit experimental in the choice of RNGs here. * * This generator is based somewhat on RC4, but has analysis * (http://ourworld.compuserve.com/homepages/bob_jenkins/randomnu.htm) * pointing to it actually being better. I like it because it's nice * and fast, and because the author did good work analyzing it. * -------------------------------------------------------------------- */#if defined __STDC__ && __STDC__# define UINT_MAX_32_BITS 4294967295U#else# define UINT_MAX_32_BITS 0xFFFFFFFF#endif#if ULONG_MAX == UINT_MAX_32_BITStypedef unsigned long word32;#else# if UINT_MAX == UINT_MAX_32_BITStypedef unsigned word32;# else# if USHRT_MAX == UINT_MAX_32_BITStypedef unsigned short word32;# else# if UCHAR_MAX == UINT_MAX_32_BITStypedef unsigned char word32;# else "No 32-bit type available!"# endif# endif# endif#endif/* Size of the state tables to use. (You may change ISAAC_LOG) */#define ISAAC_LOG 8#define ISAAC_WORDS (1 << ISAAC_LOG)#define ISAAC_BYTES (ISAAC_WORDS * sizeof (word32))/* RNG state variables */struct isaac_state { word32 mm[ISAAC_WORDS]; /* Main state array */ word32 iv[8]; /* Seeding initial vector */ word32 a, b, c; /* Extra index variables */ };/* This index operation is more efficient on many processors */#define ind(mm, x) \ (* (word32 *) ((char *) (mm) + ((x) & (ISAAC_WORDS - 1) * sizeof (word32))))/* * The central step. This uses two temporaries, x and y. mm is the * whole state array, while m is a pointer to the current word. off is * the offset from m to the word ISAAC_WORDS/2 words away in the mm array, * i.e. +/- ISAAC_WORDS/2. */#define isaac_step(mix, a, b, mm, m, off, r) \( \ a = ((a) ^ (mix)) + (m)[off], \ x = *(m), \ *(m) = y = ind (mm, x) + (a) + (b), \ *(r) = b = ind (mm, (y) >> ISAAC_LOG) + x \)/* * Refill the entire R array, and update S. */static voidisaac_refill (struct isaac_state *s, word32 r[/* ISAAC_WORDS */]){ register word32 a, b; /* Caches of a and b */ register word32 x, y; /* Temps needed by isaac_step macro */ register word32 *m = s->mm; /* Pointer into state array */ a = s->a; b = s->b + (++s->c); do { isaac_step (a << 13, a, b, s->mm, m, ISAAC_WORDS / 2, r); isaac_step (a >> 6, a, b, s->mm, m + 1, ISAAC_WORDS / 2, r + 1); isaac_step (a << 2, a, b, s->mm, m + 2, ISAAC_WORDS / 2, r + 2); isaac_step (a >> 16, a, b, s->mm, m + 3, ISAAC_WORDS / 2, r + 3); r += 4; } while ((m += 4) < s->mm + ISAAC_WORDS / 2); do { isaac_step (a << 13, a, b, s->mm, m, -ISAAC_WORDS / 2, r); isaac_step (a >> 6, a, b, s->mm, m + 1, -ISAAC_WORDS / 2, r + 1); isaac_step (a << 2, a, b, s->mm, m + 2, -ISAAC_WORDS / 2, r + 2); isaac_step (a >> 16, a, b, s->mm, m + 3, -ISAAC_WORDS / 2, r + 3); r += 4; } while ((m += 4) < s->mm + ISAAC_WORDS); s->a = a; s->b = b;}/* * The basic seed-scrambling step for initialization, based on Bob * Jenkins' 256-bit hash. */#define mix(a,b,c,d,e,f,g,h) \ ( a ^= b << 11, d += a, \ b += c, b ^= c >> 2, e += b, \ c += d, c ^= d << 8, f += c, \ d += e, d ^= e >> 16, g += d, \ e += f, e ^= f << 10, h += e, \ f += g, f ^= g >> 4, a += f, \ g += h, g ^= h << 8, b += g, \ h += a, h ^= a >> 9, c += h, \ a += b )/* The basic ISAAC initialization pass. */static voidisaac_mix (struct isaac_state *s, word32 const seed[/* ISAAC_WORDS */]){ int i; word32 a = s->iv[0]; word32 b = s->iv[1]; word32 c = s->iv[2]; word32 d = s->iv[3]; word32 e = s->iv[4]; word32 f = s->iv[5]; word32 g = s->iv[6]; word32 h = s->iv[7]; for (i = 0; i < ISAAC_WORDS; i += 8) { a += seed[i]; b += seed[i + 1]; c += seed[i + 2]; d += seed[i + 3]; e += seed[i + 4]; f += seed[i + 5]; g += seed[i + 6]; h += seed[i + 7]; mix (a, b, c, d, e, f, g, h); s->mm[i] = a; s->mm[i + 1] = b; s->mm[i + 2] = c; s->mm[i + 3] = d; s->mm[i + 4] = e; s->mm[i + 5] = f; s->mm[i + 6] = g; s->mm[i + 7] = h; } s->iv[0] = a; s->iv[1] = b; s->iv[2] = c; s->iv[3] = d; s->iv[4] = e; s->iv[5] = f; s->iv[6] = g; s->iv[7] = h;}#if 0 /* Provided for reference only; not used in this code *//* * Initialize the ISAAC RNG with the given seed material. * Its size MUST be a multiple of ISAAC_BYTES, and may be * stored in the s->mm array. * * This is a generalization of the original ISAAC initialization code * to support larger seed sizes. For seed sizes of 0 and ISAAC_BYTES, * it is identical. */static voidisaac_init (struct isaac_state *s, word32 const *seed, size_t seedsize){ static word32 const iv[8] = { 0x1367df5a, 0x95d90059, 0xc3163e4b, 0x0f421ad8, 0xd92a4a78, 0xa51a3c49, 0xc4efea1b, 0x30609119}; int i;# if 0 /* The initialization of iv is a precomputed form of: */ for (i = 0; i < 7; i++) iv[i] = 0x9e3779b9; /* the golden ratio */ for (i = 0; i < 4; ++i) /* scramble it */ mix (iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);# endif s->a = s->b = s->c = 0; for (i = 0; i < 8; i++) s->iv[i] = iv[i]; if (seedsize) { /* First pass (as in reference ISAAC code) */ isaac_mix (s, seed); /* Second and subsequent passes (extension to ISAAC) */ while (seedsize -= ISAAC_BYTES) { seed += ISAAC_WORDS; for (i = 0; i < ISAAC_WORDS; i++) s->mm[i] += seed[i]; isaac_mix (s, s->mm); } } else { /* The no seed case (as in reference ISAAC code) */ for (i = 0; i < ISAAC_WORDS; i++) s->mm[i] = 0; } /* Final pass */ isaac_mix (s, s->mm);}#endif/* Start seeding an ISAAC structire */static voidisaac_seed_start (struct isaac_state *s){ static word32 const iv[8] = { 0x1367df5a, 0x95d90059, 0xc3163e4b, 0x0f421ad8, 0xd92a4a78, 0xa51a3c49, 0xc4efea1b, 0x30609119 }; int i;#if 0 /* The initialization of iv is a precomputed form of: */ for (i = 0; i < 7; i++) iv[i] = 0x9e3779b9; /* the golden ratio */ for (i = 0; i < 4; ++i) /* scramble it */ mix (iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);#endif for (i = 0; i < 8; i++) s->iv[i] = iv[i]; /* We could initialize s->mm to zero, but why bother? */ /* s->c gets used for a data pointer during the seeding phase */ s->a = s->b = s->c = 0;}/* Add a buffer of seed material */static voidisaac_seed_data (struct isaac_state *s, void const *buf, size_t size){ unsigned char *p; size_t avail; size_t i; avail = sizeof s->mm - (size_t) s->c; /* s->c is used as a write pointer */ /* Do any full buffers that are necessary */ while (size > avail) { p = (unsigned char *) s->mm + s->c; for (i = 0; i < avail; i++) p[i] ^= ((unsigned char const *) buf)[i]; buf = (char const *) buf + avail; size -= avail; isaac_mix (s, s->mm); s->c = 0; avail = sizeof s->mm; } /* And the final partial block */ p = (unsigned char *) s->mm + s->c; for (i = 0; i < size; i++) p[i] ^= ((unsigned char const *) buf)[i]; s->c = (word32) size;}/* End of seeding phase; get everything ready to produce output. */static voidisaac_seed_finish (struct isaac_state *s){ isaac_mix (s, s->mm); isaac_mix (s, s->mm); /* Now reinitialize c to start things off right */ s->c = 0;}#define ISAAC_SEED(s,x) isaac_seed_data (s, &(x), sizeof (x))#if __GNUC__ >= 2 && (__i386__ || __alpha__)/* * Many processors have very-high-resolution timer registers, * The timer registers can be made inaccessible, so we have to deal with the * possibility of SIGILL while we're working. */static jmp_buf env;static RETSIGTYPEsigill_handler (int signum){ (void) signum;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -