Date: Mon, 12 Jul 1999 15:06:50 -0600 From: Wes Peters <wes@softweyr.com> To: Eivind Eklund <eivind@FreeBSD.ORG> Cc: cjclark@home.com, FreeBSD Security <freebsd-security@FreeBSD.ORG> Subject: Re: Secure Deletion Message-ID: <378A58EA.ACF1412F@softweyr.com> References: <199906250212.WAA07810@cc942873-a.ewndsr1.nj.home.com> <3773F67A.CC9B6215@softweyr.com> <19990629131529.A61249@bitbox.follo.net>
next in thread | previous in thread | raw e-mail | index | archive | help
Eivind Eklund wrote: > > On Fri, Jun 25, 1999 at 03:36:58PM -0600, Wes Peters wrote: > > This won't do it, if you're really interested in obliterating the file > > contents. What you want to do is overwrite the file blocks with > ^^^^ > disk > > > alternating patterns of 10101010 then 01010101 at least 100 times. > > Due to the way modern recording formats work, and the memory of the > > cells that actually store the bits on the disk, anything less won't > > really erase the disk. > > More or less correct. There are a lot of details to this, and just > writing 0x55/0xaa as normal data values won't make them hit the disk > that way. > > Since what I have to write about this topic would just end up being a > paraphrase of what Peter Gutmann has to say, I suggest you read the > paper he presented at Usenix 1996: > http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html > > Eivind. I've read Peter's paper, which I found to be very informative. I've incorporated his table of successive values into my program, along with a couple of bug fixes. (I wasn't unmapping the file before closing and unlinking it, and I was mapping it MAP_PRIVATE so it wasn't really over- writing the file anyhow. Doh!) Here's the source for the new, improved version if anyone wants to test it themselves. Unless anyone has strenuous objections, I'll make this into a port and commit it (as soon as I learn how to make a port). /* * Obliterate - a simple program to obliterate file contents. * * Copyright (c) 1999 Softweyr LLC, South Jordan, Utah USA. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY Softweyr LLC ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL Softweyr LLC OR ANY CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Author: Wes Peters * Date: Mon Jul 12 15:04:51 MDT 1999 */ #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdio.h> #include <fcntl.h> #define MIN(a,b) ((a < b) ? a : b) /* * The bit patterns used to overwrite the disk blocks. These patterns are * designed to provide a complete overwrite on all common disk recording * formats. * * Pattern devised by Peter Gutmann, Department of Computer Science, * University of Auckland <pgut001@cs.auckland.ac.nz>. See Peter's paper * "Secure Deletion of Data from Magnetic and Solid-State Memory" at * http://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html for more * information about how and why this pattern works. */ unsigned char *patterns[] = { "R", /* random */ "R", /* random */ "R", /* random */ "R", /* random */ "\x55", /* 1,7 RLL MFM */ "\xaa", /* 1,7 RLL MFM */ "\x92\x49\x24", /* 2,7 RLL MFM */ "\x49\x24\x92", /* 2,7 RLL MFM */ "\x24\x92\x49", /* 2,7 RLL MFM */ "\x00", /* 1,7 RLL 2,7 RLL */ "\x11", /* 1,7 RLL */ "\x22", /* 1,7 RLL */ "\x33", /* 1,7 RLL 2,7 RLL */ "\x44", /* 1,7 RLL */ "\x55", /* 1,7 RLL MFM */ "\x66", /* 1,7 RLL 2,7 RLL */ "\x77", /* 1,7 RLL */ "\x88", /* 1,7 RLL */ "\x99", /* 1,7 RLL 2,7 RLL */ "\xaa", /* 1,7 RLL MFM */ "\xbb", /* 1,7 RLL */ "\xcc", /* 1,7 RLL 2,7 RLL */ "\xdd", /* 1,7 RLL */ "\xee", /* 1,7 RLL */ "\xff", /* 1,7 RLL 2,7 RLL */ "\x92\x49\x24", /* 2,7 RLL MFM */ "\x49\x24\x92", /* 2,7 RLL MFM */ "\x24\x92\x49", /* 2,7 RLL MFM */ "\x6d\xb6\xdb", /* 2,7 RLL */ "\xb6\xdb\x6d", /* 2,7 RLL */ "\xdb\x6d\xb6", /* 2,7 RLL */ "R", /* random */ "R", /* random */ "R", /* random */ "R", /* random */ }; static int npatterns = sizeof (patterns) / sizeof (patterns[0]); /* * A file handle to access the system pool of randomness. */ int randfd = 0; /* * Fill a block of memory with a specified pattern, repeating the pattern as * necessary to completely fill the block. This routine is smart about * "special" patterns such as an apparent NULL pattern (this means zero-fill * the block) and "R" which means fill the block with random values. */ int fill(void *data, off_t size, char *pattern) { /* * If the first byte is zero, it means zero-fill the block. */ if (*pattern == '\0') { (void) memset(data, 0, size); } /* * If the first byte is 'R' it means random fill the block. We use the * system pool of randomness here because it is an easy to use source of * pretty much random data. Reading blocks of any appreciable size from * the pool probably degrades it into a cascade of MD5 signatures, but * should be sufficient for our needs here. */ else if (*pattern == 'R') { read(randfd, data, size); } else { /* * Be smart about using library functions where available. */ int l = strlen(pattern); if (l == 1) { memset(data, *pattern, size); } else { char *p, *e = data + size; for (p = data; p < e; p += l) { memcpy(p, pattern, MIN(l, e - p)); } } } } /* * Overwrite the named file. Return 0 on success, -1 otherwise. */ int obliterate(char *fname) { struct stat S; int fd; void *data; int iteration; if (stat(fname, &S) == -1) { perror(fname); return -1; } if (!S_ISREG(S.st_mode)) { fprintf(stderr, "%s: not a regular file\n", fname); return -1; } fd = open(fname, O_RDWR); if (fd == -1) { perror(fname); return -1; } data = mmap(NULL, S.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { perror(fname); close(fd); return -1; } /* * Overwrite the file with successive patterns as specified above. */ for (iteration = 0; iteration < npatterns; iteration++) { fill(data, S.st_size, patterns[iteration]); if (fsync(fd) == -1) { perror(fname); close(fd); return -1; } } /* * Get rid of the file (from the filesystem point of view). */ if (munmap(data, S.st_size) == -1) { perror(fname); close(fd); return -1; } close(fd); if (unlink(fname) == -1) { perror(fname); return -1; } return 0; } /* * Obliterate each file named on the command line. */ int main(int argc, char *argv[]) { int result = 0; /* * Open the system entropy pool for random data. */ if ((randfd = open("/dev/urandom", O_RDONLY)) == -1) { perror("Opening system pool of randomness (/dev/urandom)"); return -1; } while (--argc) { result |= obliterate(*++argv); } close(randfd); return result; } /* EOF */ -- "Where am I, and what am I doing in this handbasket?" Wes Peters Softweyr LLC http://softweyr.com/ wes@softweyr.com To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?378A58EA.ACF1412F>