Compare commits
25 Commits
aa47e2f24a
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ec2a3dde5 | |||
| a8f384b201 | |||
| 668bab17c6 | |||
| ff69e14c94 | |||
| a73a06cc61 | |||
| a1c9dd3fdb | |||
| a755899f8a | |||
| d79c89fd37 | |||
| 638414b873 | |||
| 99576d7c40 | |||
| 2aeead77e9 | |||
| e0fce04767 | |||
| 9ae39356a9 | |||
| 0c3234dec5 | |||
| fb4f59e123 | |||
| f96f255f3e | |||
| f8365df8cf | |||
| f744fd0f3d | |||
| c41d5ab89e | |||
| b70c3cc0c4 | |||
| 75198873e5 | |||
| 34db75be21 | |||
| fe94c0b5af | |||
| 3de4f887d2 | |||
| e68400ebc9 |
@@ -0,0 +1,35 @@
|
||||
CC=gcc
|
||||
OPT=-O2 -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
|
||||
INSTALL_DIR=/usr/local/bin
|
||||
MAN_DIR=/usr/local/man
|
||||
OPT_MOD=-D__KERNEL__ -DMODULE -fomit-frame-pointer -fno-strict-aliasing -pipe
|
||||
|
||||
all: sdel-lib.o srm sfill sswap smem
|
||||
|
||||
sdel-lib.o: sdel-lib.c
|
||||
$(CC) ${OPT} -c sdel-lib.c
|
||||
|
||||
srm: srm.c
|
||||
$(CC) ${OPT} -o srm srm.c sdel-lib.o
|
||||
-strip srm
|
||||
sfill: sfill.c
|
||||
$(CC) ${OPT} -o sfill sfill.c sdel-lib.o
|
||||
-strip sfill
|
||||
sswap: sswap.c
|
||||
$(CC) ${OPT} -o sswap sswap.c sdel-lib.o
|
||||
-strip sswap
|
||||
smem: smem.c
|
||||
$(CC) ${OPT} -o smem smem.c sdel-lib.o
|
||||
-strip smem
|
||||
|
||||
clean:
|
||||
rm -f sfill srm sswap smem sdel sdel-lib.o core *~
|
||||
|
||||
install: all
|
||||
mkdir -p -m 755 ${INSTALL_DIR} 2> /dev/null
|
||||
rm -f sdel && ln -s srm sdel
|
||||
cp -f sdel srm sfill sswap smem the_cleaner.sh ${INSTALL_DIR}
|
||||
chmod 711 ${INSTALL_DIR}/srm ${INSTALL_DIR}/sfill ${INSTALL_DIR}/sswap ${INSTALL_DIR}/smem ${INSTALL_DIR}/the_cleaner.sh
|
||||
mkdir -p -m 755 ${MAN_DIR}/man1 2> /dev/null
|
||||
cp -f srm.1 sfill.1 sswap.1 smem.1 ${MAN_DIR}/man1
|
||||
chmod 644 ${MAN_DIR}/man1/srm.1 ${MAN_DIR}/man1/sfill.1 ${MAN_DIR}/man1/sswap.1 ${MAN_DIR}/man1/smem.1
|
||||
@@ -0,0 +1 @@
|
||||
# [Original Project is secure-delete here](https://github.com/BlackArch/secure-delete)
|
||||
@@ -0,0 +1,5 @@
|
||||
#define BLOCKSIZE 32769 /* must be mod 3 = 0, should be >= 16k */
|
||||
#define RANDOM_DEVICE "/dev/urandom" /* must not exist */
|
||||
#define DIR_SEPERATOR '/' /* '/' on unix, '\' on dos/win */
|
||||
#define FLUSH sync() /* system call to flush the disk */
|
||||
#define MAXINODEWIPE 4194304 /* 22 bits */
|
||||
@@ -0,0 +1,235 @@
|
||||
--- src/rm.c.orig Sat Nov 23 23:11:12 1996
|
||||
+++ src/rm.c Sun Jan 24 13:37:20 1999
|
||||
@@ -1,3 +1,10 @@
|
||||
+/* patch for rm from fileutils-3.16 to support secure data deletion
|
||||
+ * to be activated by -s. -sss gives full erasure security (38 overwrites)
|
||||
+ * This patch is from the secure_delete-2.0.tar.gz package available
|
||||
+ * at http://www.thehackerschoice.com - get it, and read the documentation!
|
||||
+ * (c)1999 by van Hauser / [THC] - The Hacker's Choice, vh@reptile.rug.ac.be
|
||||
+ */
|
||||
+
|
||||
/* `rm' file deletion utility for GNU.
|
||||
Copyright (C) 88, 90, 91, 94, 95, 1996 Free Software Foundation, Inc.
|
||||
|
||||
@@ -21,6 +28,11 @@
|
||||
#include <stdio.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/types.h>
|
||||
+/* SRM BEGIN */
|
||||
+#include <sys/stat.h>
|
||||
+#include <unistd.h>
|
||||
+#include <stdlib.h>
|
||||
+/* SRM END */
|
||||
|
||||
#include "system.h"
|
||||
#include "error.h"
|
||||
@@ -50,6 +62,14 @@
|
||||
int yesno ();
|
||||
void strip_trailing_slashes ();
|
||||
|
||||
+/* SRM BEGIN */
|
||||
+#define BLOCKSIZE 32769
|
||||
+#define DIR_SEPERATOR '/'
|
||||
+#define FLUSH sync()
|
||||
+#define RANDOM_DEVICE "/dev/urandom"
|
||||
+/* SRM END */
|
||||
+
|
||||
+static int secure_delete ();
|
||||
static int clear_directory __P ((struct stat *statp));
|
||||
static int duplicate_entry __P ((struct pathstack *stack, ino_t inum));
|
||||
static int remove_dir __P ((struct stat *statp));
|
||||
@@ -68,6 +88,12 @@
|
||||
/* Path of file now being processed; extended as necessary. */
|
||||
static char *pathname;
|
||||
|
||||
+/* SRM BEGIN */
|
||||
+static int secure; /* secure overwrite mode */
|
||||
+static char fillbuf[BLOCKSIZE];
|
||||
+static FILE *devrandom;
|
||||
+/* SRM END */
|
||||
+
|
||||
/* Number of bytes currently allocated for `pathname';
|
||||
made larger when necessary, but never smaller. */
|
||||
static int pnsize;
|
||||
@@ -104,6 +130,9 @@
|
||||
{"force", no_argument, NULL, 'f'},
|
||||
{"interactive", no_argument, NULL, 'i'},
|
||||
{"recursive", no_argument, &recursive, 1},
|
||||
+/* SRM BEGIN */
|
||||
+ {"secure_delete", no_argument, NULL, 's'},
|
||||
+/* SRM END */
|
||||
{"verbose", no_argument, &verbose, 1},
|
||||
{"help", no_argument, &show_help, 1},
|
||||
{"version", no_argument, &show_version, 1},
|
||||
@@ -125,8 +154,8 @@
|
||||
= unlink_dirs = 0;
|
||||
pnsize = 256;
|
||||
pathname = xmalloc (pnsize);
|
||||
-
|
||||
- while ((c = getopt_long (argc, argv, "dfirvR", long_opts, (int *) 0)) != EOF)
|
||||
+
|
||||
+ while ((c = getopt_long (argc, argv, "dfirsvR", long_opts, (int *) 0)) != EOF)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -147,6 +176,11 @@
|
||||
case 'R':
|
||||
recursive = 1;
|
||||
break;
|
||||
+/* SRM BEGIN */
|
||||
+ case 's':
|
||||
+ secure++;
|
||||
+ break;
|
||||
+/* SRM END */
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
@@ -198,6 +232,116 @@
|
||||
exit (err > 0);
|
||||
}
|
||||
|
||||
+/* SRM BEGIN */
|
||||
+
|
||||
+void fill_buf(char pattern[3]) {
|
||||
+ int loop;
|
||||
+ int where;
|
||||
+ for (loop = 0; loop < (BLOCKSIZE / 3); loop++) {
|
||||
+ where = loop * 3;
|
||||
+ fillbuf[where] = pattern[0];
|
||||
+ fillbuf[where+1] = pattern[1];
|
||||
+ fillbuf[where+2] = pattern[2];
|
||||
+ }
|
||||
+}
|
||||
+void random_buf() {
|
||||
+ int loop;
|
||||
+ if (devrandom != NULL)
|
||||
+ for (loop = 0; loop < BLOCKSIZE; loop++)
|
||||
+ fillbuf[loop] = (unsigned char) (256.0*rand()/(RAND_MAX+1.0));
|
||||
+ else
|
||||
+ fread(&fillbuf, BLOCKSIZE, 1, devrandom);
|
||||
+}
|
||||
+
|
||||
+/* overwriting the file several times */
|
||||
+
|
||||
+ static int
|
||||
+ secure_delete (delfile)
|
||||
+ char *delfile;
|
||||
+ {
|
||||
+ unsigned char write_modes[27][3] = {
|
||||
+ {"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"}, {"\x49\x24\x92"},
|
||||
+ {"\x24\x92\x49"}, {"\x00\x00\x00"}, {"\x11\x11\x11"}, {"\x22\x22\x22"},
|
||||
+ {"\x33\x33\x33"}, {"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
|
||||
+ {"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"}, {"\xaa\xaa\xaa"},
|
||||
+ {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"}, {"\xdd\xdd\xdd"}, {"\xee\xee\xee"},
|
||||
+ {"\xff\xff\xff"}, {"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
|
||||
+ {"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
|
||||
+ };
|
||||
+ unsigned char std_array[3] = "\xff\xff\xff";
|
||||
+ FILE *f;
|
||||
+ int file;
|
||||
+ unsigned long writes;
|
||||
+ unsigned long counter;
|
||||
+ unsigned long filesize;
|
||||
+ struct stat filestat;
|
||||
+ int turn;
|
||||
+ int result;
|
||||
+ unsigned char ch;
|
||||
+ char newname[512];
|
||||
+
|
||||
+/* open the file, get the filesize, calculate the numbers of needed writings */
|
||||
+ if (lstat(delfile, &filestat))
|
||||
+ return 1;
|
||||
+ if (! S_ISREG(filestat.st_mode))
|
||||
+ return 1;
|
||||
+ if ((f = fopen(delfile, "r+b")) == NULL)
|
||||
+ return 1;
|
||||
+ filesize = filestat.st_size;
|
||||
+ writes = (1 + (filesize / BLOCKSIZE));
|
||||
+ file=fileno(f);
|
||||
+ (void) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
+ devrandom = fopen(RANDOM_DEVICE, "r");
|
||||
+
|
||||
+ if (verbose)
|
||||
+ printf(" ");
|
||||
+
|
||||
+
|
||||
+ if (secure > 1) {
|
||||
+ fill_buf(std_array);
|
||||
+ for (counter=1; counter<=writes; counter++)
|
||||
+ fwrite(&fillbuf, 1, BLOCKSIZE, f);
|
||||
+ if (verbose)
|
||||
+ printf("*");
|
||||
+ fflush(f);
|
||||
+ fsync(file);
|
||||
+ }
|
||||
+
|
||||
+/* do the overwriting stuff */
|
||||
+ for (turn=0; turn<=36; turn++) {
|
||||
+ rewind(f);
|
||||
+ if ((secure < 3) && (turn > 0)) break;
|
||||
+ if ((turn>=5) && (turn<=31)) {
|
||||
+ fill_buf(write_modes[turn-5]);
|
||||
+ for (counter=1; counter<=writes; counter++)
|
||||
+ fwrite(&fillbuf, 1, BLOCKSIZE, f);
|
||||
+ } else {
|
||||
+ for (counter=1; counter<=writes; counter++) {
|
||||
+ random_buf();
|
||||
+ fwrite(&fillbuf, 1, BLOCKSIZE, f);
|
||||
+ }
|
||||
+ }
|
||||
+ fflush(f);
|
||||
+ if (fsync(file) < 0)
|
||||
+ FLUSH;
|
||||
+ if (verbose)
|
||||
+ printf("*");
|
||||
+ }
|
||||
+ (void) fclose(f);
|
||||
+ (void) fclose(devrandom);
|
||||
+/* Hard Flush -> Force cached data to be written to disk */
|
||||
+ FLUSH;
|
||||
+/* open + truncating the file, so an attacker doesn't know the diskblocks */
|
||||
+ if ((file = open(delfile, O_WRONLY | O_TRUNC)) >= 0)
|
||||
+ close(file);
|
||||
+ if (verbose)
|
||||
+ printf(" wiped\n");
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/* SRM END */
|
||||
+
|
||||
/* Remove file or directory `pathname' after checking appropriate things.
|
||||
Return 0 if `pathname' is removed, 1 if not. */
|
||||
|
||||
@@ -264,8 +408,16 @@
|
||||
return 1;
|
||||
}
|
||||
|
||||
- if (verbose)
|
||||
- printf ("%s\n", pathname);
|
||||
+ if (verbose) {
|
||||
+ printf ("%s", pathname);
|
||||
+ if (secure == 0)
|
||||
+ printf ("\n");
|
||||
+ }
|
||||
+
|
||||
+/* SRM BEGIN */
|
||||
+ if (secure)
|
||||
+ secure_delete(pathname);
|
||||
+/* SRM END */
|
||||
|
||||
if (unlink (pathname) && (errno != ENOENT || !ignore_missing_files))
|
||||
{
|
||||
@@ -536,11 +688,13 @@
|
||||
-f, --force ignore nonexistent files, never prompt\n\
|
||||
-i, --interactive prompt before any removal\n\
|
||||
-r, -R, --recursive remove the contents of directories recursively\n\
|
||||
+ -s, --secure_delete secure overwrite (-sss for full security)\n\
|
||||
-v, --verbose explain what is being done\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
"));
|
||||
puts (_("\nReport bugs to fileutils-bugs@gnu.ai.mit.edu"));
|
||||
+ puts (_("\nWith secure_delete patch by van Hauser <vh@reptile.rug.ac.be>"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
--- remove.c.orig 2003-05-05 15:15:48.000000000 +0200
|
||||
+++ remove.c 2003-05-05 15:26:08.000000000 +0200
|
||||
@@ -26,6 +26,12 @@
|
||||
#include <sys/types.h>
|
||||
#include <assert.h>
|
||||
|
||||
+/* SRM BEGIN */
|
||||
+#include <sys/stat.h>
|
||||
+#include <unistd.h>
|
||||
+#include <stdlib.h>
|
||||
+/* SRM END */
|
||||
+
|
||||
#if HAVE_STDBOOL_H
|
||||
# include <stdbool.h>
|
||||
#else
|
||||
@@ -81,6 +87,18 @@
|
||||
int euidaccess ();
|
||||
int yesno ();
|
||||
|
||||
+/* SRM BEGIN */
|
||||
+#define BLOCKSIZE 32769
|
||||
+#define DIR_SEPERATOR '/'
|
||||
+#define FLUSH sync()
|
||||
+#define RANDOM_DEVICE "/dev/urandom"
|
||||
+static int secure = 0;
|
||||
+static char fillbuf[BLOCKSIZE];
|
||||
+static FILE *devrandom;
|
||||
+/* Functions */
|
||||
+static int secure_delete();
|
||||
+/* SRM END */
|
||||
+
|
||||
extern char *program_name;
|
||||
|
||||
/* state initialized by remove_init, freed by remove_fini */
|
||||
@@ -605,6 +623,103 @@
|
||||
return status;
|
||||
}
|
||||
|
||||
+/* SRM BEGIN */
|
||||
+void fill_buf(char pattern[3]) {
|
||||
+ int loop;
|
||||
+ int where;
|
||||
+ for (loop = 0; loop < (BLOCKSIZE / 3); loop++) {
|
||||
+ where = loop * 3;
|
||||
+ fillbuf[where] = pattern[0];
|
||||
+ fillbuf[where+1] = pattern[1];
|
||||
+ fillbuf[where+2] = pattern[2];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void random_buf() {
|
||||
+ int loop;
|
||||
+ if (devrandom != NULL)
|
||||
+ for (loop = 0; loop < BLOCKSIZE; loop++)
|
||||
+ fillbuf[loop] = (unsigned char) (256.0*rand()/(RAND_MAX+1.0));
|
||||
+ else
|
||||
+ fread(&fillbuf, BLOCKSIZE, 1, devrandom);
|
||||
+}
|
||||
+
|
||||
+/* overwriting the file several times */
|
||||
+ static int
|
||||
+ secure_delete (delfile)
|
||||
+ char *delfile;
|
||||
+ {
|
||||
+ unsigned char write_modes[27][3] = {
|
||||
+ {"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"}, {"\x49\x24\x92"},
|
||||
+ {"\x24\x92\x49"}, {"\x00\x00\x00"}, {"\x11\x11\x11"}, {"\x22\x22\x22"},
|
||||
+ {"\x33\x33\x33"}, {"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
|
||||
+ {"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"}, {"\xaa\xaa\xaa"},
|
||||
+ {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"}, {"\xdd\xdd\xdd"}, {"\xee\xee\xee"},
|
||||
+ {"\xff\xff\xff"}, {"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
|
||||
+ {"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
|
||||
+ };
|
||||
+ unsigned char std_array[3] = "\xff\xff\xff";
|
||||
+ FILE *f;
|
||||
+ int file;
|
||||
+ unsigned long writes;
|
||||
+ unsigned long counter;
|
||||
+ unsigned long filesize;
|
||||
+ struct stat filestat;
|
||||
+ int turn;
|
||||
+ int result;
|
||||
+ unsigned char ch;
|
||||
+ char newname[512];
|
||||
+
|
||||
+/* open the file, get the filesize, calculate the numbers of needed writings */
|
||||
+ if (lstat(delfile, &filestat))
|
||||
+ return 1;
|
||||
+ if (! S_ISREG(filestat.st_mode))
|
||||
+ return 1;
|
||||
+ if ((f = fopen(delfile, "r+b")) == NULL)
|
||||
+ return 1;
|
||||
+ filesize = filestat.st_size;
|
||||
+ writes = (1 + (filesize / BLOCKSIZE));
|
||||
+ file=fileno(f);
|
||||
+ (void) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
+ devrandom = fopen(RANDOM_DEVICE, "r");
|
||||
+
|
||||
+ if (secure > 1) {
|
||||
+ fill_buf(std_array);
|
||||
+ for (counter=1; counter<=writes; counter++)
|
||||
+ fwrite(&fillbuf, 1, BLOCKSIZE, f);
|
||||
+ fflush(f);
|
||||
+ fsync(file);
|
||||
+ }
|
||||
+
|
||||
+/* do the overwriting stuff */
|
||||
+ for (turn=0; turn<=36; turn++) {
|
||||
+ rewind(f);
|
||||
+ if ((secure < 3) && (turn > 0)) break;
|
||||
+ if ((turn>=5) && (turn<=31)) {
|
||||
+ fill_buf(write_modes[turn-5]);
|
||||
+ for (counter=1; counter<=writes; counter++)
|
||||
+ fwrite(&fillbuf, 1, BLOCKSIZE, f);
|
||||
+ } else {
|
||||
+ for (counter=1; counter<=writes; counter++) {
|
||||
+ random_buf();
|
||||
+ fwrite(&fillbuf, 1, BLOCKSIZE, f);
|
||||
+ }
|
||||
+ }
|
||||
+ fflush(f);
|
||||
+ if (fsync(file) < 0)
|
||||
+ FLUSH;
|
||||
+ }
|
||||
+ (void) fclose(f);
|
||||
+ (void) fclose(devrandom);
|
||||
+/* Hard Flush -> Force cached data to be written to disk */
|
||||
+ FLUSH;
|
||||
+/* open + truncating the file, so an attacker doesn't know the diskblocks */
|
||||
+ if ((file = open(delfile, O_WRONLY | O_TRUNC)) >= 0)
|
||||
+ close(file);
|
||||
+ return 0;
|
||||
+}
|
||||
+/* SRM END */
|
||||
+
|
||||
/* Query the user if appropriate, and if ok try to remove the
|
||||
file or directory specified by FS. Return RM_OK if it is removed,
|
||||
and RM_ERROR or RM_USER_DECLINED if not. */
|
||||
@@ -646,9 +761,16 @@
|
||||
return RM_USER_DECLINED;
|
||||
}
|
||||
|
||||
- if (x->verbose)
|
||||
- printf (_("removing %s\n"), quote (full_filename (pathname)));
|
||||
+ if (x->verbose) {
|
||||
+ if (secure)
|
||||
+ printf (_("wiping %s\n"), quote (full_filename (pathname)));
|
||||
+ else
|
||||
+ printf (_("removing %s\n"), quote (full_filename (pathname)));
|
||||
+ }
|
||||
|
||||
+ if (secure)
|
||||
+ secure_delete(pathname);
|
||||
+
|
||||
if (unlink (pathname) && (errno != ENOENT || !x->ignore_missing_files))
|
||||
{
|
||||
error (0, errno, _("cannot unlink %s"), quote (full_filename (pathname)));
|
||||
@@ -821,6 +943,8 @@
|
||||
{
|
||||
mode_t filetype_mode;
|
||||
|
||||
+ secure = x->secure;
|
||||
+
|
||||
if (user_specified_name)
|
||||
{
|
||||
/* CAUTION: this use of base_name works only because any
|
||||
--- rm.c.orig 2003-05-05 14:58:35.000000000 +0200
|
||||
+++ rm.c 2003-05-05 15:16:31.000000000 +0200
|
||||
@@ -58,7 +58,7 @@
|
||||
#define PROGRAM_NAME "rm"
|
||||
|
||||
#define AUTHORS \
|
||||
- "Paul Rubin, David MacKenzie, Richard Stallman, and Jim Meyering"
|
||||
+ "Paul Rubin, David MacKenzie, Richard Stallman, Jim Meyering, and van Hauser"
|
||||
|
||||
void strip_trailing_slashes ();
|
||||
|
||||
@@ -71,6 +71,9 @@
|
||||
{"force", no_argument, NULL, 'f'},
|
||||
{"interactive", no_argument, NULL, 'i'},
|
||||
{"recursive", no_argument, NULL, 'r'},
|
||||
+/* SRM BEGIN */
|
||||
+ {"secure", no_argument, NULL, 's'},
|
||||
+/* SRM END */
|
||||
{"verbose", no_argument, NULL, 'v'},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
@@ -93,6 +96,7 @@
|
||||
-f, --force ignore nonexistent files, never prompt\n\
|
||||
-i, --interactive prompt before any removal\n\
|
||||
-r, -R, --recursive remove the contents of directories recursively\n\
|
||||
+ -s, --secure secure overwrite (-sss for full security)\n\
|
||||
-v, --verbose explain what is being done\n\
|
||||
--help display this help and exit\n\
|
||||
--version output version information and exit\n\
|
||||
@@ -105,10 +109,11 @@
|
||||
\n\
|
||||
Note that if you use rm to remove a file, it is usually possible to recover\n\
|
||||
the contents of that file. If you want more assurance that the contents are\n\
|
||||
-truly unrecoverable, consider using shred.\n\
|
||||
+truly unrecoverable, use the -s option.\n\
|
||||
"),
|
||||
program_name, program_name);
|
||||
puts (_("\nReport bugs to <bug-fileutils@gnu.org>."));
|
||||
+ puts (_("\nWith secure_delete patch by van Hauser <vh@thc.org>"));
|
||||
}
|
||||
exit (status);
|
||||
}
|
||||
@@ -122,6 +127,7 @@
|
||||
x->recursive = 0;
|
||||
x->stdin_tty = isatty (STDIN_FILENO);
|
||||
x->verbose = 0;
|
||||
+ x->secure = 0;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -140,7 +146,7 @@
|
||||
|
||||
rm_option_init (&x);
|
||||
|
||||
- while ((c = getopt_long (argc, argv, "dfirvR", long_opts, NULL)) != -1)
|
||||
+ while ((c = getopt_long (argc, argv, "dfirsvR", long_opts, NULL)) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -161,6 +167,11 @@
|
||||
case 'R':
|
||||
x.recursive = 1;
|
||||
break;
|
||||
+/* SRM BEGIN */
|
||||
+ case 's':
|
||||
+ x.secure++;
|
||||
+ break;
|
||||
+/* SRM END */
|
||||
case 'v':
|
||||
x.verbose = 1;
|
||||
break;
|
||||
--- remove.h.orig 2003-05-05 15:13:47.000000000 +0200
|
||||
+++ remove.h 2003-05-05 15:14:13.000000000 +0200
|
||||
@@ -18,6 +18,9 @@
|
||||
Only works for the super-user. */
|
||||
int unlink_dirs;
|
||||
|
||||
+ /* If nonzero, secure overwrites file contents */
|
||||
+ int secure;
|
||||
+
|
||||
/* If nonzero, display the name of each file removed. */
|
||||
int verbose;
|
||||
};
|
||||
@@ -0,0 +1,349 @@
|
||||
/* Secure Delete Library - by van Hauser / [THC], vh@thc.org
|
||||
*
|
||||
* Secure Delete Library provides the following public functions:
|
||||
*
|
||||
* void sdel_init(int secure_random)
|
||||
* Initializiation function for sdel_overwrite. It needs to be called
|
||||
* once at program start, not for each file to be overwritten.
|
||||
* Options:
|
||||
* secure_random - if != 0 defines that the secure random number
|
||||
* generator RANDOM_DEVICE should be used
|
||||
*
|
||||
* void sdel_finnish()
|
||||
* Clean-up function, if sdel_init() was called in a program. It needs
|
||||
* only to be called at the end of the program.
|
||||
*
|
||||
* int sdel_overwrite(int mode, int fd, long start, unsigned long bufsize,
|
||||
* unsigned long length, int zero)
|
||||
* This is the heart of sdel-lib. It overwrites the target file
|
||||
* descriptor securely to make life hard even for the NSA.
|
||||
* Read the next paragraph for the techniques.
|
||||
* Options:
|
||||
* mode = 0 - once overwrite with random data
|
||||
* 1 - once overwrite with 0xff, then once with random data
|
||||
* 2 - overwrite 38 times with special values
|
||||
* fd - filedescriptor of the target to overwrite
|
||||
* start - where to start overwriting. 0 is from the beginning
|
||||
* this is needed for wiping swap spaces etc.
|
||||
* bufsize - size of the buffer to use for overwriting, depends
|
||||
* on the filesystem
|
||||
* length - amount of data to write (file size), 0 means until
|
||||
* an error occurs
|
||||
* zero - last wipe is zero bytes, not random
|
||||
* returns 0 on success, -1 on errors
|
||||
*
|
||||
* int sdel_unlink(char *filename, int directory, int truncate, int slow)
|
||||
* First truncates the file (if it is not a directory), then renames it
|
||||
* and finally rmdir/unlinks the target.
|
||||
* Options:
|
||||
* filename - filename/directory to unlink/rmdir
|
||||
* directory - if != 0, it is a directory
|
||||
* truncate - if != 0, it truncates the file
|
||||
* slow - is either O_SYNC (see open(2)) or 0
|
||||
* returns 0 on success, -1 on errors
|
||||
*
|
||||
* Compiles clean on OpenBSD, Linux, Solaris, AIX and I guess all others.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* For security reasons full 32kb blocks are written so that the whole block
|
||||
* on which the file(s) live are overwritten. (change #define #BLOCKSIZE)
|
||||
* Standard mode is a real security wipe for 38 times, flushing
|
||||
* the caches after every write. The wipe technique was proposed by Peter
|
||||
* Gutmann at Usenix '96 and includes 10 random overwrites plus 28 special
|
||||
* defined characters. Take a look at the paper of him, it's really worth
|
||||
* your time.
|
||||
*
|
||||
* Read the manual for limitations.
|
||||
*/
|
||||
|
||||
#include "sdel-lib.h"
|
||||
|
||||
//
|
||||
// STARTING FUNCTIONS
|
||||
//
|
||||
|
||||
void __sdel_fill_buf(char pattern[3], unsigned long bufsize, char *buf) {
|
||||
int loop;
|
||||
int where;
|
||||
|
||||
for (loop = 0; loop < (bufsize / 3); loop++) {
|
||||
where = loop * 3;
|
||||
*buf++ = pattern[0];
|
||||
*buf++ = pattern[1];
|
||||
*buf++ = pattern[2];
|
||||
}
|
||||
}
|
||||
|
||||
void __sdel_random_buf(unsigned long bufsize, char *buf) {
|
||||
int loop;
|
||||
|
||||
if (devrandom == NULL)
|
||||
for (loop = 0; loop < bufsize; loop++)
|
||||
*buf++ = (unsigned char) (256.0*rand()/(RAND_MAX+1.0));
|
||||
else
|
||||
fread(buf, bufsize, 1, devrandom);
|
||||
}
|
||||
|
||||
void __sdel_random_filename(char *filename) {
|
||||
int i;
|
||||
for (i = strlen(filename) - 1;
|
||||
(filename[i] != DIR_SEPERATOR) && (i >= 0);
|
||||
i--)
|
||||
if (filename[i] != '.') /* keep dots in the filename */
|
||||
filename[i] = 97+(int) ((int) ((256.0 * rand()) / (RAND_MAX + 1.0)) % 26);
|
||||
}
|
||||
|
||||
void sdel_init(int secure_random) {
|
||||
|
||||
(void) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
(void) setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
if (BLOCKSIZE<16384)
|
||||
fprintf(stderr, "Programming Warning: in-compiled blocksize is <16k !\n");
|
||||
if (BLOCKSIZE % 3 > 0)
|
||||
fprintf(stderr, "Programming Error: in-compiled blocksize is not a multiple of 3!\n");
|
||||
|
||||
srand( (getpid()+getuid()+getgid()) ^ time(0) );
|
||||
devrandom = NULL;
|
||||
#ifdef RANDOM_DEVICE
|
||||
if (secure_random) {
|
||||
if ((devrandom = fopen(RANDOM_DEVICE, "r")) != NULL)
|
||||
if (verbose)
|
||||
printf("Using %s for random input.\n", RANDOM_DEVICE);
|
||||
}
|
||||
#endif
|
||||
|
||||
__internal_sdel_init = 1;
|
||||
}
|
||||
|
||||
void sdel_finnish() {
|
||||
if (devrandom != NULL) {
|
||||
fclose(devrandom);
|
||||
devrandom = NULL;
|
||||
}
|
||||
if (! __internal_sdel_init) {
|
||||
fprintf(stderr, "Programming Error: sdel-lib was not initialized before calling sdel_finnish().\n");
|
||||
return;
|
||||
}
|
||||
__internal_sdel_init = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* secure_overwrite function parameters:
|
||||
* mode = 0 : once overwrite with random data
|
||||
* 1 : once overwrite with 0xff, then once with random data
|
||||
* 2 : overwrite 38 times with special values
|
||||
* fd : filedescriptor of the target to overwrite
|
||||
* start : where to start overwriting. 0 is from the beginning
|
||||
* bufsize : size of the buffer to use for overwriting, depends on the filesystem
|
||||
* length : amount of data to write (file size), 0 means until an error occurs
|
||||
*
|
||||
* returns 0 on success, -1 on errors
|
||||
*/
|
||||
int sdel_overwrite(int mode, int fd, long start, unsigned long bufsize, unsigned long length, int zero) {
|
||||
unsigned long writes;
|
||||
unsigned long counter;
|
||||
int turn;
|
||||
int last = 0;
|
||||
char buf[65535];
|
||||
FILE *f;
|
||||
|
||||
if (! __internal_sdel_init)
|
||||
fprintf(stderr, "Programming Error: sdel-lib was not initialized before sdel_overwrite().\n");
|
||||
|
||||
if ((f = fdopen(fd, "r+b")) == NULL)
|
||||
return -1;
|
||||
|
||||
/* calculate the number of writes */
|
||||
if (length > 0)
|
||||
writes = (1 + (length / bufsize));
|
||||
else
|
||||
writes = 0;
|
||||
|
||||
/* do the first overwrite */
|
||||
if (start == 0)
|
||||
rewind(f);
|
||||
else
|
||||
if (fseek(f, start, SEEK_SET) != 0)
|
||||
return -1;
|
||||
if (mode != 0 || zero) {
|
||||
if (mode == 0)
|
||||
__sdel_fill_buf(std_array_00, bufsize, buf);
|
||||
else
|
||||
__sdel_fill_buf(std_array_ff, bufsize, buf);
|
||||
if (writes > 0)
|
||||
for (counter=1; counter<=writes; counter++)
|
||||
fwrite(&buf, 1, bufsize, f); // dont care for errors
|
||||
else
|
||||
do {} while(fwrite(&buf, 1, bufsize, f) == bufsize);
|
||||
if (verbose)
|
||||
printf("*");
|
||||
fflush(f);
|
||||
if (fsync(fd) < 0)
|
||||
FLUSH;
|
||||
if (mode == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* do the rest of the overwriting stuff */
|
||||
for (turn = 0; turn <= 36; turn++) {
|
||||
if (start == 0)
|
||||
rewind(f);
|
||||
else
|
||||
if (fseek(f, start, SEEK_SET) != 0)
|
||||
return -1;
|
||||
if ((mode < 2) && (turn > 0))
|
||||
break;
|
||||
if ((turn >= 5) && (turn <= 31)) {
|
||||
__sdel_fill_buf(write_modes[turn-5], bufsize, buf);
|
||||
if (writes > 0)
|
||||
for (counter = 1; counter <= writes; counter++)
|
||||
fwrite(&buf, 1, bufsize, f); // dont care for errors
|
||||
else
|
||||
do {} while(fwrite(&buf, 1, bufsize, f) == bufsize);
|
||||
} else {
|
||||
if (zero && ((mode == 2 && turn == 36) || mode == 1)) {
|
||||
last = 1;
|
||||
__sdel_fill_buf(std_array_00, bufsize, buf);
|
||||
}
|
||||
if (writes > 0) {
|
||||
for (counter = 1; counter <= writes; counter++) {
|
||||
if (! last)
|
||||
__sdel_random_buf(bufsize, buf);
|
||||
fwrite(&buf, 1, bufsize, f); // dont care for errors
|
||||
}
|
||||
} else {
|
||||
do {
|
||||
if (! last)
|
||||
__sdel_random_buf(bufsize, buf);
|
||||
} while (fwrite(&buf, 1, bufsize, f) == bufsize); // dont care for errors
|
||||
}
|
||||
}
|
||||
fflush(f);
|
||||
if (fsync(fd) < 0)
|
||||
FLUSH;
|
||||
if (verbose)
|
||||
printf("*");
|
||||
}
|
||||
|
||||
(void) fclose(f);
|
||||
/* Hard Flush -> Force cached data to be written to disk */
|
||||
FLUSH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* secure_unlink function parameters:
|
||||
* filename : the file or directory to remove
|
||||
* directory : defines if the filename poses a directory
|
||||
* truncate : truncate file
|
||||
* slow : do things slowly, to prevent caching
|
||||
*
|
||||
* returns 0 on success, -1 on errors.
|
||||
*/
|
||||
int sdel_unlink(char *filename, int directory, int truncate, int slow) {
|
||||
int fd;
|
||||
int turn = 0;
|
||||
int result;
|
||||
char newname[strlen(filename) + 1];
|
||||
struct stat filestat;
|
||||
|
||||
/* open + truncating the file, so an attacker doesn't know the diskblocks */
|
||||
if (! directory && truncate)
|
||||
if ((fd = open(filename, O_WRONLY | O_TRUNC | slow)) >= 0)
|
||||
close(fd);
|
||||
|
||||
/* Generate random unique name, renaming and deleting of the file */
|
||||
strcpy(newname, filename); // not a buffer overflow as it has got the exact length
|
||||
|
||||
do {
|
||||
__sdel_random_filename(newname);
|
||||
if ((result = lstat(newname, &filestat)) >= 0)
|
||||
turn++;
|
||||
} while ((result >= 0) && (turn <= 100));
|
||||
|
||||
if (turn <= 100) {
|
||||
result = rename(filename, newname);
|
||||
if (result != 0) {
|
||||
fprintf(stderr, "Warning: Couldn't rename %s - ", filename);
|
||||
perror("");
|
||||
strcpy(newname, filename);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"Warning: Couldn't find a free filename for %s!\n",filename);
|
||||
strcpy(newname, filename);
|
||||
}
|
||||
|
||||
if (directory) {
|
||||
result = rmdir(newname);
|
||||
if (result) {
|
||||
printf("Warning: Unable to remove directory %s - ", filename);
|
||||
perror("");
|
||||
(void) rename(newname, filename);
|
||||
} else
|
||||
if (verbose)
|
||||
printf("Removed directory %s ...", filename);
|
||||
} else {
|
||||
result = unlink(newname);
|
||||
if (result) {
|
||||
printf("Warning: Unable to unlink file %s - ", filename);
|
||||
perror("");
|
||||
(void) rename(newname, filename);
|
||||
} else
|
||||
if (verbose)
|
||||
printf(" Removed file %s ...", filename);
|
||||
}
|
||||
|
||||
if (result != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sdel_wipe_inodes(char *loc, char **array) {
|
||||
char *template = malloc(strlen(loc) + 16);
|
||||
int i = 0;
|
||||
int fail = 0;
|
||||
int fd;
|
||||
|
||||
if (verbose)
|
||||
printf("Wiping inodes ...");
|
||||
|
||||
array = malloc(MAXINODEWIPE * sizeof(template));
|
||||
strcpy(template, loc);
|
||||
if (loc[strlen(loc) - 1] != '/')
|
||||
strcat(template, "/");
|
||||
strcat(template, "xxxxxxxx.xxx");
|
||||
|
||||
while(i < MAXINODEWIPE && fail < 5) {
|
||||
__sdel_random_filename(template);
|
||||
if (open(template, O_CREAT | O_EXCL | O_WRONLY, 0600) < 0)
|
||||
fail++;
|
||||
else {
|
||||
array[i] = malloc(strlen(template));
|
||||
strcpy(array[i], template);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
FLUSH;
|
||||
|
||||
if (fail < 5) {
|
||||
fprintf(stderr, "Warning: could not wipe all inodes!\n");
|
||||
}
|
||||
|
||||
array[i] = NULL;
|
||||
fd = 0;
|
||||
while(fd < i) {
|
||||
unlink(array[fd]);
|
||||
free(array[fd]);
|
||||
fd++;
|
||||
}
|
||||
free(array);
|
||||
array = NULL;
|
||||
FLUSH;
|
||||
if (verbose)
|
||||
printf(" Done ... ");
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#ifndef _SDEL_LIB_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
//
|
||||
// STARTING CONSTANTS AND VARIABLES
|
||||
//
|
||||
|
||||
unsigned char write_modes[27][3] = {
|
||||
{"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"}, {"\x49\x24\x92"},
|
||||
{"\x24\x92\x49"}, {"\x00\x00\x00"}, {"\x11\x11\x11"}, {"\x22\x22\x22"},
|
||||
{"\x33\x33\x33"}, {"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
|
||||
{"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"}, {"\xaa\xaa\xaa"},
|
||||
{"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"}, {"\xdd\xdd\xdd"}, {"\xee\xee\xee"},
|
||||
{"\xff\xff\xff"}, {"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
|
||||
{"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
|
||||
};
|
||||
unsigned char std_array_ff[3] = "\xff\xff\xff";
|
||||
unsigned char std_array_00[3] = "\x00\x00\x00";
|
||||
|
||||
FILE *devrandom = NULL;
|
||||
int verbose = 0;
|
||||
int __internal_sdel_init = 0;
|
||||
|
||||
#define _SDEL_LIB_H_
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef _SDEL_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define VERSION "v3.1"
|
||||
#define AUTHOR "van Hauser / THC"
|
||||
#define EMAIL "vh@thc.org"
|
||||
#define WEB "http://www.thc.org"
|
||||
|
||||
#ifndef O_SYNC
|
||||
#ifdef O_FSYNC
|
||||
#define O_SYNC O_FSYNC
|
||||
#else
|
||||
#define O_SYNC 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef O_LARGEFILE
|
||||
#define O_LARGEFILE 0
|
||||
#endif
|
||||
|
||||
char *prg;
|
||||
|
||||
extern int verbose;
|
||||
|
||||
extern void sdel_init(int secure_random);
|
||||
extern void sdel_finnish();
|
||||
extern int sdel_overwrite(int mode, int fd, long start, unsigned long bufsize, unsigned long length, int zero);
|
||||
extern int sdel_unlink(char *filename, int directory, int truncate, int slow);
|
||||
extern void sdel_wipe_inodes(char *loc, char **array);
|
||||
extern void __sdel_fill_buf(char pattern[3], unsigned long bufsize, char *buf);
|
||||
extern void __sdel_random_buf(unsigned long bufsize, char *buf);
|
||||
extern void __sdel_random_filename(char *filename);
|
||||
|
||||
#define _SDEL_H
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
.\" This definition swiped from the gcc(1) man page
|
||||
.de Sp
|
||||
.if n .sp
|
||||
.if t .sp 0.4
|
||||
..
|
||||
.TH SFILL 1
|
||||
|
||||
.SH NAME
|
||||
sfill \- secure free disk and inode space wiper (secure_deletion toolkit)
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B sfill [-f] [-i] [-I] [-l] [-l] [-v] [-z] directory/mountpoint
|
||||
|
||||
.SH DESCRIPTION
|
||||
.I sfill
|
||||
is designed to delete data which lies on available diskspace on mediums
|
||||
in a secure manner which can not be recovered by thiefs, law enforcement
|
||||
or other threats.
|
||||
The wipe algorythm is based on the paper "Secure Deletion of Data from
|
||||
Magnetic and Solid-State Memory" presented at the 6th Usenix Security
|
||||
Symposium by Peter Gutmann, one of the leading civilian cryptographers.
|
||||
.PP
|
||||
The
|
||||
.I secure data deletion
|
||||
process of sfill goes like this:
|
||||
.PP
|
||||
.TP
|
||||
.B *
|
||||
1 pass with 0xff
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.TP
|
||||
.B *
|
||||
27 passes with special values defined by Peter Gutmann.
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.PP
|
||||
afterwards as many temporary files as possible are generated to wipe the
|
||||
free inode space. After no more temporary files can be created, they are
|
||||
removed and sfill is finnished.
|
||||
.PP
|
||||
|
||||
.SH COMMANDLINE OPTIONS
|
||||
.PP
|
||||
.TP
|
||||
.B \-f
|
||||
fast (and insecure mode): no /dev/urandom, no synchronize mode.
|
||||
.TP
|
||||
.B \-i
|
||||
wipe only free inode space, not free disk space
|
||||
.TP
|
||||
.B \-I
|
||||
wipe only free disk space, not free inode space
|
||||
.TP
|
||||
.B \-l
|
||||
lessens the security. Only two passes are written: one mode with 0xff
|
||||
and a final mode with random values.
|
||||
.TP
|
||||
.B \-l
|
||||
-l for a second time lessons the security even more: only one random pass
|
||||
is written.
|
||||
.TP
|
||||
.B \-v
|
||||
verbose mode
|
||||
.TP
|
||||
.B \-z
|
||||
wipes the last write with zeros instead of random data
|
||||
.PP
|
||||
.PP
|
||||
.B directory/mountpoint
|
||||
this is the location of the file created in your filesystem. It should
|
||||
lie on the partition you want to write.
|
||||
.PP
|
||||
|
||||
.SH LIMITATIONS
|
||||
.TP
|
||||
.B FILESYSTEM INTELLIGENCE
|
||||
Most filesystems (ext2, ffs, etc.) have several features included to enhance
|
||||
performance, which will result in that sfill might not receive all available
|
||||
free space. Sad but true. Nothing can be done about that ...
|
||||
.TP
|
||||
.B NFS
|
||||
Beware of NFS. You can't ensure you really completely wiped your data
|
||||
from the remote disks. (especially because of caching)
|
||||
.TP
|
||||
.B Raid
|
||||
Raid Systems use stripped disks and have got large caches. It's hard to wipe
|
||||
them.
|
||||
.TP
|
||||
.B swap
|
||||
Some of your data might have a copy in your swapspace.
|
||||
.I sswap
|
||||
is available for this task.
|
||||
|
||||
.PP
|
||||
.SH BUGS
|
||||
No bugs. There was never a bug in the secure_deletion package (in contrast
|
||||
to my other tools, whew, good luck ;-)
|
||||
Send me any that you find. Patches are nice too :)
|
||||
|
||||
.SH AUTHOR
|
||||
.Sp
|
||||
van Hauser / THC
|
||||
.I <vh@thc.org>
|
||||
|
||||
.SH DISTRIBUTION
|
||||
The newest version of the
|
||||
.I secure_deletion package
|
||||
can be obtained from
|
||||
.I http://www.thc.org
|
||||
.Sp
|
||||
.I sfill
|
||||
and the
|
||||
.I secure_deletion package
|
||||
is (C) 1997-2003 by van Hauser / THC (vh@thc.org)
|
||||
.Sp
|
||||
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; Version 2.
|
||||
.Sp
|
||||
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.
|
||||
|
||||
.SH SEE ALSO
|
||||
.I srm
|
||||
(1),
|
||||
.I sswap
|
||||
(1),
|
||||
.I smem
|
||||
(1)
|
||||
@@ -0,0 +1,237 @@
|
||||
/* Secure FILL - by van Hauser / [THC], vh@thc.org
|
||||
*
|
||||
* Secure FILL overwrites all available free diskspace by creating a file,
|
||||
* wiping all free diskspace it gets and finally deleting the file.
|
||||
*
|
||||
* Standard mode is a real security wipe for 38 times, flushing
|
||||
* the caches after every write. The wipe technique was proposed by Peter
|
||||
* Gutmann at Usenix '96 and includes 10 random overwrites plus 28 special
|
||||
* defined characters. Take a look at the paper of him, it's really worth
|
||||
* your time.
|
||||
* The option -l overwrites two times the data. (0xff + random)
|
||||
* The option -ll overwrites the data once. (random)
|
||||
* New with v2.3: wipes all inodes in the defined directory
|
||||
*
|
||||
* Read the manual for limitations.
|
||||
* Compiles clean on OpenBSD, Linux, Solaris and AIX
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "sdel.h"
|
||||
|
||||
#ifdef BLOCKSIZE
|
||||
#undef BLOCKSIZE
|
||||
#endif
|
||||
#define BLOCKSIZE 65535
|
||||
#define MAXINODEWIPE 4194304 /* 22 bits */
|
||||
|
||||
char **array = NULL;
|
||||
int slow = O_SYNC;
|
||||
int debug = 1;
|
||||
int zero = 0;
|
||||
int inode_only = 0;
|
||||
int fd = -1;
|
||||
char *filename = NULL;
|
||||
FILE *f;
|
||||
|
||||
void help() {
|
||||
printf("sfill %s (c) 1997-2003 by %s <%s>\n\n", VERSION, AUTHOR, EMAIL);
|
||||
printf("Syntax: %s [-fiIlvz] directory\n\n", prg);
|
||||
printf("Options:\n");
|
||||
printf("\t-f fast (and insecure mode): no /dev/urandom, no synchronize mode.\n");
|
||||
printf("\t-i wipe only inodes in the directory specified\n");
|
||||
printf("\t-I just wipe space, not inodes\n");
|
||||
printf("\t-l lessens the security (use twice for total insecure mode).\n");
|
||||
printf("\t-v is verbose mode.\n");
|
||||
printf("\t-z last wipe writes zeros, not random data.\n");
|
||||
printf("\nsfill does a secure overwrite of the free space on the partition the specified\ndirectory resides and all free inodes of the directory specified.\n");
|
||||
printf("Default is secure mode (38 writes).\n");
|
||||
printf("You can find updates at %s\n", WEB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void cleanup(int signo) {
|
||||
fprintf(stderr,"\nTerminated by signal. Clean exit.\n");
|
||||
if (fd > 0) {
|
||||
fsync(fd);
|
||||
(void) close(fd);
|
||||
sync();
|
||||
if (filename != NULL && unlink(filename) != 0)
|
||||
fprintf(stderr, "Error: Could not remove temporary file %s!\n", filename);
|
||||
}
|
||||
if (array != NULL) {
|
||||
int i = 0;
|
||||
while(array[i] != NULL) {
|
||||
unlink(array[i]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
int result;
|
||||
int secure = 2; /* standard is secure mode */
|
||||
int loop;
|
||||
int turn;
|
||||
int counter;
|
||||
struct stat filestat;
|
||||
struct rlimit rlim;
|
||||
char type[15] = "random";
|
||||
|
||||
if (getuid() != 0)
|
||||
fprintf(stderr,"Warning: you are not root. You might not be able to wipe the whole filesystem.\n");
|
||||
|
||||
prg = argv[0];
|
||||
if (argc == 1 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--h", 3) == 0)
|
||||
help();
|
||||
|
||||
while (1) {
|
||||
result = getopt(argc, argv, "fFiIlLsSvVzZ");
|
||||
if (result < 0)
|
||||
break;
|
||||
switch (result) {
|
||||
case 'f' :
|
||||
case 'F' : slow = 0;
|
||||
break;
|
||||
case 'i' : inode_only = 1;
|
||||
break;
|
||||
case 'I' : inode_only = -1;
|
||||
break;
|
||||
case 'l' :
|
||||
case 'L' : if (secure) secure--;
|
||||
break;
|
||||
case 's' :
|
||||
case 'S' : secure++;
|
||||
break;
|
||||
case 'v' :
|
||||
case 'V' : verbose++;
|
||||
break;
|
||||
case 'Z' :
|
||||
case 'z' : zero++;
|
||||
break;
|
||||
default : help();
|
||||
}
|
||||
}
|
||||
loop = optind;
|
||||
if (loop >= argc)
|
||||
help();
|
||||
if (zero) strcpy(type, "zero");
|
||||
|
||||
do {
|
||||
char newname[strlen(argv[loop]) + 16];
|
||||
strcpy(newname, argv[loop]); // can not overflow
|
||||
if (opendir(newname) == NULL) { /* no need for ensuring close */
|
||||
fprintf(stderr, "Error: %s is not a directory\n", newname);
|
||||
} else {
|
||||
|
||||
/* Generate random unique name for tempfile */
|
||||
srand(getpid()+getuid());
|
||||
|
||||
if (newname[strlen(newname)-1] != DIR_SEPERATOR)
|
||||
strcat(newname, "/");
|
||||
|
||||
turn = 0; result = 0;
|
||||
strcat(newname, "oooooooo.ooo");
|
||||
result = lstat(newname, &filestat);
|
||||
|
||||
while ((result >= 0) && (turn <= 250)) {
|
||||
for (counter = strlen(newname)-1;
|
||||
(newname[counter] != DIR_SEPERATOR);
|
||||
counter--)
|
||||
if (newname[counter] != '.')
|
||||
newname[counter] = 97+(int) (27.0 * rand() / (RAND_MAX + 1.0));
|
||||
if ((result = lstat(newname, &filestat)) >= 0)
|
||||
turn++;
|
||||
};
|
||||
if (result >= 0)
|
||||
fprintf(stderr,"Error: couldn't find a free filename in %s\n",argv[loop]);
|
||||
else {
|
||||
signal(SIGINT, cleanup);
|
||||
signal(SIGTERM, cleanup);
|
||||
signal(SIGHUP, cleanup);
|
||||
|
||||
sdel_init(slow);
|
||||
|
||||
if (verbose && inode_only < 1) {
|
||||
switch (secure) {
|
||||
case 0 : printf("Wipe mode is insecure (one pass [%s])\n",type);
|
||||
break;
|
||||
case 1 : printf("Wipe mode is insecure (two passes [0xff/%s])\n",type);
|
||||
break;
|
||||
default: printf("Wipe mode is secure (38 special passes)\n");
|
||||
}
|
||||
printf("Wiping now ...\n");
|
||||
}
|
||||
|
||||
#ifdef RLIM_INFINITY
|
||||
#ifdef RLIMIT_FSIZE
|
||||
rlim.rlim_cur = RLIM_INFINITY;
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
if (setrlimit(RLIMIT_FSIZE, &rlim) != 0)
|
||||
fprintf(stderr, "Warning: Could not reset ulimit for filesize.\n");
|
||||
#else
|
||||
fprintf(stderr, "Warning: not compiled with support for resetting ulimit for filesize.\n");
|
||||
#endif
|
||||
#else
|
||||
fprintf(stderr, "Warning: not compiled with support for resetting ulimit for filesize.\n");
|
||||
#endif
|
||||
|
||||
result = 9;
|
||||
if (inode_only < 1) {
|
||||
/* create the file */
|
||||
if (verbose) printf("Creating %s ... ", newname);
|
||||
if ((fd = open(newname, O_RDWR | O_EXCL | O_CREAT | O_LARGEFILE | slow, 0600 )) < 0)
|
||||
result = 1;
|
||||
else {
|
||||
filename = newname;
|
||||
result = sdel_overwrite(secure, fd, 0, BLOCKSIZE, 0, zero);
|
||||
/* Hard Flush -> Force cached data to be written to disk - the defines above! */
|
||||
FLUSH;
|
||||
if ((fd = open(newname, O_WRONLY | O_TRUNC)) >= 0)
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
if ((result == 0 && inode_only == 0) || inode_only > 0) {
|
||||
if (result == 0 && inode_only == 0)
|
||||
printf(" ");
|
||||
sdel_wipe_inodes(argv[loop], array);
|
||||
result = 0;
|
||||
}
|
||||
|
||||
switch (result) {
|
||||
case 0 : if (verbose) printf(" Finished\n");
|
||||
break;
|
||||
case 1 : fprintf(stderr, "Error: No write permission for %s. ", argv[loop]);
|
||||
perror("");
|
||||
break;
|
||||
case 9: break;
|
||||
default: fprintf(stderr, "Unknown error\n");
|
||||
}
|
||||
if (unlink(newname) != 0)
|
||||
fprintf(stderr, "Error: Could not remove temporary file %s!\n", newname);
|
||||
filename = NULL;
|
||||
}
|
||||
}
|
||||
loop++;
|
||||
} while (loop < argc);
|
||||
|
||||
sdel_finnish();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
.\" This definition swiped from the gcc(1) man page
|
||||
.de Sp
|
||||
.if n .sp
|
||||
.if t .sp 0.4
|
||||
..
|
||||
.TH SMEM 1
|
||||
|
||||
.SH NAME
|
||||
smem \- secure memory wiper (secure_deletion toolkit)
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B smem [-f] [-l] [-l] [-v]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.I smem
|
||||
is designed to delete data which may lie still in your memory (RAM)
|
||||
in a secure manner which can not be recovered by thiefs, law enforcement
|
||||
or other threats.
|
||||
Note that with the new SDRAMs, data will not wither away but will be kept
|
||||
static - it is easy to extract the necessary information!
|
||||
The wipe algorythm is based on the paper "Secure Deletion of Data from
|
||||
Magnetic and Solid-State Memory" presented at the 6th Usenix Security
|
||||
Symposium by Peter Gutmann, one of the leading civilian cryptographers.
|
||||
.PP
|
||||
The
|
||||
.I secure data deletion
|
||||
process of smem goes like this:
|
||||
.PP
|
||||
.TP
|
||||
.B *
|
||||
1 pass with 0x00
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.TP
|
||||
.B *
|
||||
27 passes with special values defined by Peter Gutmann.
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.PP
|
||||
|
||||
.SH COMMANDLINE OPTIONS
|
||||
.PP
|
||||
.TP
|
||||
.B \-f
|
||||
fast (and insecure mode): no /dev/urandom.
|
||||
.TP
|
||||
.B \-l
|
||||
lessens the security. Only two passes are written: the first with 0x00
|
||||
and a final random one.
|
||||
.TP
|
||||
.B \-l
|
||||
-l for a second time lessons the security even more: only one pass with
|
||||
0x00 is written.
|
||||
.TP
|
||||
.B \-v
|
||||
verbose mode
|
||||
.PP
|
||||
|
||||
.SH BEWARE
|
||||
.TP
|
||||
.B SLOW
|
||||
Wiping the memory is very slow. You might use smem with the -ll option. (tip)
|
||||
.TP
|
||||
.B BETA!
|
||||
.I smem
|
||||
is still beta.
|
||||
|
||||
.PP
|
||||
.SH BUGS
|
||||
No bugs. There was never a bug in the secure_deletion package (in contrast
|
||||
to my other tools, whew, good luck ;-)
|
||||
Send me any that you find. Patches are nice too :)
|
||||
|
||||
.SH AUTHOR
|
||||
.Sp
|
||||
van Hauser / THC
|
||||
.I <vh@thc.org>
|
||||
|
||||
.SH DISTRIBUTION
|
||||
The newest version of the
|
||||
.I secure_deletion package
|
||||
can be obtained from
|
||||
.I http://www.thc.org
|
||||
.Sp
|
||||
.I smem
|
||||
and the
|
||||
.I secure_deletion package
|
||||
is (C) 1997-2003 by van Hauser / THC (vh@thc.org)
|
||||
.Sp
|
||||
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; Version 2.
|
||||
.Sp
|
||||
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.
|
||||
|
||||
.SH SEE ALSO
|
||||
.I srm
|
||||
(1),
|
||||
.I sfill
|
||||
(1),
|
||||
.I sswap
|
||||
(1)
|
||||
@@ -0,0 +1,209 @@
|
||||
/* Secure MEMORY cleaner - by van Hauser / [THC], vh@thc.org
|
||||
*
|
||||
* Note that this program is beta. It was tested with linux, solaris and
|
||||
* openbsd but I can't tell for other platforms.
|
||||
*
|
||||
* Secure MEMORY overwrites all data in your memory it gets.
|
||||
* The any -l option this does a real security wipe for 38 times, flushing
|
||||
* the caches after every write. The wipe technique was proposed by Peter
|
||||
* Gutmann at Usenix '96 and includes 10 random overwrites plus 29 special
|
||||
* defined characters. Take a look at the paper of him, it's really worth
|
||||
* your time.
|
||||
* If run with one -l option, it wipes the memory twice, first with null
|
||||
* bytes, then with random values.
|
||||
* If run with two -l options, it wipes the memory only once with null bytes.
|
||||
*
|
||||
* Note that it is *very* slow. You might run it with "-llf"
|
||||
*
|
||||
* Read the manual for limitations.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "sdel.h"
|
||||
|
||||
#ifdef BLOCKSIZE
|
||||
#undef BLOCKSIZE
|
||||
#endif
|
||||
#define BLOCKSIZE 65536
|
||||
|
||||
char buf[BLOCKSIZE+2];
|
||||
int slow = 1;
|
||||
|
||||
extern FILE *devrandom;
|
||||
|
||||
void help() {
|
||||
printf("smem %s (c) 1997-2003 by %s <%s>\n\n", VERSION, AUTHOR, EMAIL);
|
||||
printf("Syntax: %s [-flv]\n\n", prg);
|
||||
printf("Options:\n");
|
||||
printf("\t-f fast (and insecure mode): no /dev/urandom.\n");
|
||||
printf("\t-l lessens the security (use twice for total insecure mode).\n");
|
||||
printf("\t-v is verbose mode.\n");
|
||||
printf("\nsmem does a secure overwrite of the memory (RAM), because memory contents can\n");
|
||||
printf("be recovered even after a shutdown! Default is secure mode (38 writes).\n");
|
||||
printf("You can find updates at %s\n", WEB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int smash_it(int mode) {
|
||||
unsigned char write_modes[27][3] = {
|
||||
{"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"}, {"\x49\x24\x92"},
|
||||
{"\x24\x92\x49"}, {"\x00\x00\x00"}, {"\x11\x11\x11"}, {"\x22\x22\x22"},
|
||||
{"\x33\x33\x33"}, {"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
|
||||
{"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"}, {"\xaa\xaa\xaa"},
|
||||
{"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"}, {"\xdd\xdd\xdd"}, {"\xee\xee\xee"},
|
||||
{"\xff\xff\xff"}, {"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
|
||||
{"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
|
||||
};
|
||||
|
||||
int turn;
|
||||
unsigned int counter = 0;
|
||||
unsigned char buffers[27][BLOCKSIZE+2];
|
||||
char *ptr;
|
||||
struct rlimit rlim;
|
||||
|
||||
if (verbose) {
|
||||
switch (mode) {
|
||||
case 0 : printf("Wipe mode is insecure (one pass with 0x00)\n");
|
||||
break;
|
||||
case 1 : printf("Wipe mode is insecure (two passes [0x00/random])\n"); break;
|
||||
default: printf("Wipe mode is secure (38 special passes)\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (slow && mode)
|
||||
if ((devrandom = fopen(RANDOM_DEVICE, "r")) != NULL)
|
||||
if (verbose)
|
||||
printf("Using %s for random input.\n", RANDOM_DEVICE);
|
||||
|
||||
/* We set a new ulimit, so we can grab all memory ... */
|
||||
#ifdef RLIM_INFINITY
|
||||
rlim.rlim_cur = RLIM_INFINITY;
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
#ifdef RLIMIT_DATA
|
||||
if (setrlimit(RLIMIT_DATA, &rlim) != 0)
|
||||
fprintf(stderr, "Warning: Could not reset ulimit for data.\n");
|
||||
#endif
|
||||
#ifdef RLIMIT_STACK
|
||||
if (setrlimit(RLIMIT_STACK, &rlim) != 0)
|
||||
fprintf(stderr, "Warning: Could not reset ulimit for stack.\n");
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
if (setrlimit(RLIMIT_RSS, &rlim) != 0)
|
||||
fprintf(stderr, "Warning: Could not reset ulimit for rss.\n");
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
if (setrlimit(RLIMIT_MEMLOCK, &rlim) != 0)
|
||||
fprintf(stderr, "Warning: Could not reset ulimit for mem locked.\n");
|
||||
#endif
|
||||
#ifndef RLIMIT_DATA
|
||||
#ifndef RLIMIT_STACK
|
||||
#ifndef RLIMIT_RSS
|
||||
#ifndef RLIMIT_MEMLOCK
|
||||
fprintf(stderr, "Warning: Not compiled with support for resetting ulimits for memory\n");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
fprintf(stderr, "Warning: Not compiled with support for resetting ulimits for memory\n");
|
||||
#endif
|
||||
|
||||
if (mode > 1) {
|
||||
for (turn=0; turn<27; turn++) {
|
||||
__sdel_fill_buf(write_modes[turn], BLOCKSIZE + 2, buf);
|
||||
memcpy(buffers[turn], buf, BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
alarm(600); /* needed to prevent mem caching */
|
||||
|
||||
while ( (ptr = calloc(4096, 16)) != NULL) {
|
||||
if (mode > 0) {
|
||||
for (turn=0; turn<=36; turn++) {
|
||||
if ((mode == 1) && (turn > 0)) break;
|
||||
if ((turn>=5) && (turn<=31)) {
|
||||
memcpy(ptr, buffers[turn-5], BLOCKSIZE);
|
||||
} else {
|
||||
__sdel_random_buf(BLOCKSIZE + 2, buf);
|
||||
memcpy(ptr, buf, BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (verbose && (counter > 8)) { /* every 512kb */
|
||||
printf("*");
|
||||
counter = 0;
|
||||
} else counter++;
|
||||
}
|
||||
|
||||
if (devrandom)
|
||||
fclose(devrandom);
|
||||
if (verbose)
|
||||
printf(" done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
fprintf(stderr,"Terminated by signal. Clean exit.\n");
|
||||
if (devrandom)
|
||||
fclose(devrandom);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
int secure = 2;
|
||||
int result;
|
||||
|
||||
prg = argv[0];
|
||||
if (argc == 2)
|
||||
if ( (strncmp(argv[1],"-h", 2) == 0) || (strcmp(argv[1],"-?") == 0) )
|
||||
help();
|
||||
|
||||
while (1) {
|
||||
result = getopt(argc, argv, "FfLlSsVvZz");
|
||||
if (result<0) break;
|
||||
switch (result) {
|
||||
case 'F' :
|
||||
case 'f' : slow = 0;
|
||||
break;
|
||||
case 'L' :
|
||||
case 'l' : if (secure) secure--;
|
||||
break;
|
||||
case 'S' :
|
||||
case 's' : secure++;
|
||||
break;
|
||||
case 'V' :
|
||||
case 'v' : verbose++;
|
||||
break;
|
||||
case 'Z':
|
||||
case 'z': break;
|
||||
default : help();
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc)
|
||||
help();
|
||||
|
||||
printf("Starting Wiping the memory, press Control-C to abort earlier. Help: \"%s -h\"\n", prg);
|
||||
|
||||
(void) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
signal(SIGINT, cleanup);
|
||||
signal(SIGTERM, cleanup);
|
||||
signal(SIGHUP, cleanup);
|
||||
signal(SIGALRM, cleanup);
|
||||
|
||||
smash_it(secure);
|
||||
|
||||
/* thats all */
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
.\" This definition swiped from the gcc(1) man page
|
||||
.de Sp
|
||||
.if n .sp
|
||||
.if t .sp 0.4
|
||||
..
|
||||
.TH SRM 1
|
||||
|
||||
.SH NAME
|
||||
srm \- secure remove (secure_deletion toolkit)
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B srm [-d] [-f] [-l] [-l] [-r] [-v] [-z] files
|
||||
|
||||
.SH DESCRIPTION
|
||||
.I srm
|
||||
is designed to delete data on mediums in a secure manner which can not be
|
||||
recovered by thiefs, law enforcement or other threats.
|
||||
The wipe algorythm is based on the paper "Secure Deletion of Data from
|
||||
Magnetic and Solid-State Memory" presented at the 6th Usenix Security
|
||||
Symposium by Peter Gutmann, one of the leading civilian cryptographers.
|
||||
.PP
|
||||
The
|
||||
.I secure data deletion
|
||||
process of srm goes like this:
|
||||
.PP
|
||||
.TP
|
||||
.B *
|
||||
1 pass with 0xff
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.TP
|
||||
.B *
|
||||
27 passes with special values defined by Peter Gutmann.
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.TP
|
||||
.B *
|
||||
Rename the file to a random value
|
||||
.TP
|
||||
.B *
|
||||
Truncate the file
|
||||
.PP
|
||||
.PP
|
||||
As an additional measure of security, the file is opened in O_SYNC mode
|
||||
and after each pass an fsync() call is done.
|
||||
.I srm
|
||||
writes 32k blocks for the purpose of speed, filling buffers of disk caches
|
||||
to force them to flush and overwriting old data which belonged to the file.
|
||||
.PP
|
||||
|
||||
.SH COMMANDLINE OPTIONS
|
||||
.PP
|
||||
.TP
|
||||
.B \-d
|
||||
ignore the two special dot files . and .. on the commandline. (so you can
|
||||
execute it like "srm -d .* *")
|
||||
.TP
|
||||
.B \-f
|
||||
fast (and insecure mode): no /dev/urandom, no synchronize mode.
|
||||
.TP
|
||||
.B \-l
|
||||
lessens the security. Only two passes are written: one mode with 0xff
|
||||
and a final mode random values.
|
||||
.TP
|
||||
.B \-l
|
||||
-l for a second time lessons the security even more: only one random pass
|
||||
is written.
|
||||
.TP
|
||||
.B \-r
|
||||
recursive mode, deletes all subdirectories.
|
||||
.TP
|
||||
.B \-v
|
||||
verbose mode
|
||||
.TP
|
||||
.B \-z
|
||||
wipes the last write with zeros instead of random data
|
||||
.PP
|
||||
|
||||
.SH LIMITATIONS
|
||||
.TP
|
||||
.B NFS
|
||||
Beware of NFS. You can't ensure you really completely wiped your data
|
||||
from the remote disks.
|
||||
.TP
|
||||
.B Raid
|
||||
Raid Systems use stripped disks and have got large caches. It's hard to wipe
|
||||
them.
|
||||
.TP
|
||||
.B swap, /tmp, etc.
|
||||
Some of your data might have a temporary (deleted) copy somewhere on the
|
||||
disk. You should use
|
||||
.I sfill
|
||||
which comes with the
|
||||
.I secure_deletion package
|
||||
to ensure to wipe also the free diskspace. However, If already a small
|
||||
file aquired a block with your precious data, no tool known to me can help
|
||||
you here. For a secure deletion of the swap space
|
||||
.I sswap
|
||||
is available.
|
||||
|
||||
.PP
|
||||
.SH BUGS
|
||||
No bugs. There was never a bug in the secure_deletion package (in contrast
|
||||
to my other tools, whew, good luck ;-)
|
||||
Send me any that you find. Patches are nice too :)
|
||||
|
||||
.SH AUTHOR
|
||||
.Sp
|
||||
van Hauser / THC
|
||||
.I <vh@thc.org>
|
||||
|
||||
.SH DISTRIBUTION
|
||||
The newest version of the
|
||||
.I secure_deletion package
|
||||
can be obtained from
|
||||
.I http://www.thc.org
|
||||
.Sp
|
||||
.I srm
|
||||
and the
|
||||
.I secure_deletion package
|
||||
is (C) 1997-2003 by van Hauser / THC (vh@thc.org)
|
||||
.Sp
|
||||
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; Version 2.
|
||||
.Sp
|
||||
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.
|
||||
|
||||
.SH SEE ALSO
|
||||
.I sfill
|
||||
(1),
|
||||
.I sswap
|
||||
(1),
|
||||
.I smem
|
||||
(1)
|
||||
@@ -0,0 +1,309 @@
|
||||
/* Secure RM - by van Hauser / [THC], vh@thc.org
|
||||
*
|
||||
* Secure ReMove first overwrites then renames and finally deletes the target
|
||||
* file(s) specified via parameters.
|
||||
* For security reasons full 32kb blocks are written so that the whole block
|
||||
* on which the file(s) live are overwritten. (change #define #BLOCKSIZE)
|
||||
* The option -l overwrites two times the data.
|
||||
* The option -ll overwrites the data once.
|
||||
* Standard mode is a real security wipe for 38 times, flushing
|
||||
* the caches after every write. The wipe technique was proposed by Peter
|
||||
* Gutmann at Usenix '96 and includes 10 random overwrites plus 28 special
|
||||
* defined characters. Take a look at the paper of him, it's really worth
|
||||
* your time.
|
||||
*
|
||||
* Advice : set "alias rm 'srm -v'"
|
||||
*
|
||||
* Read the manual for limitations.
|
||||
* Compiles clean on OpenBSD, Linux, Solaris, AIX and I guess all others.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <signal.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include "sdel.h"
|
||||
|
||||
int slow = O_SYNC;
|
||||
int recursive = 0;
|
||||
int zero = 0;
|
||||
unsigned long bufsize = BLOCKSIZE;
|
||||
int fd;
|
||||
|
||||
void help () {
|
||||
printf("srm %s (c) 1997-2003 by %s <%s>\n\n", VERSION, AUTHOR, EMAIL);
|
||||
printf("Syntax: %s [-dflrvz] file1 file2 etc.\n\n", prg);
|
||||
printf("Options:\n");
|
||||
printf("\t-d ignore the two dot special files \".\" and \"..\".\n");
|
||||
printf("\t-f fast (and insecure mode): no /dev/urandom, no synchronize mode.\n");
|
||||
printf("\t-l lessens the security (use twice for total insecure mode).\n");
|
||||
printf("\t-r recursive mode, deletes all subdirectories.\n");
|
||||
printf("\t-v is verbose mode.\n");
|
||||
printf("\t-z last wipe writes zeros instead of random data.\n");
|
||||
printf("\nsrm does a secure overwrite/rename/delete of the target file(s).\n");
|
||||
printf("Default is secure mode (38 writes).\n");
|
||||
printf("You can find updates at %s\n", WEB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int smash_it(char *filename, int mode) {
|
||||
struct stat filestat;
|
||||
struct stat controlstat;
|
||||
int i_am_a_directory = 0;
|
||||
|
||||
/* get the file stats */
|
||||
if (lstat(filename, &filestat))
|
||||
return 1;
|
||||
|
||||
if (S_ISREG(filestat.st_mode) && filestat.st_nlink > 1) {
|
||||
fprintf(stderr, "Error: File %s - file is hardlinked %d time(s), skipping!\n", filename, filestat.st_nlink - 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if the blocksize on the filesystem is bigger than the on compiled with, enlarge! */
|
||||
if (filestat.st_blksize > bufsize) {
|
||||
if (filestat.st_blksize > 65532) {
|
||||
bufsize = 65535;
|
||||
} else {
|
||||
bufsize = (((filestat.st_blksize / 3) + 1) * 3);
|
||||
}
|
||||
}
|
||||
|
||||
/* handle the recursive mode */
|
||||
if (recursive)
|
||||
if (S_ISDIR(filestat.st_mode)) {
|
||||
DIR *dir;
|
||||
struct dirent *dir_entry;
|
||||
struct stat cwd_stat;
|
||||
char current_dir[4097];
|
||||
int res;
|
||||
int chdir_success = 1;
|
||||
|
||||
if (verbose) printf("DIRECTORY (going recursive now)\n");
|
||||
getcwd(current_dir, 4096);
|
||||
current_dir[4096] = '\0';
|
||||
|
||||
/* a won race will chmod a file to 0700 if the user is owner/root
|
||||
I'll think about a secure solution to this, however, I think
|
||||
there isn't one - anyone with an idea? */
|
||||
if (chdir(filename)) {
|
||||
(void) chmod(filename, 0700); /* ignore permission errors */
|
||||
if (chdir(filename)) {
|
||||
fprintf(stderr,"Can't chdir() to %s, hence I can't wipe it.\n", filename);
|
||||
chdir_success = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (chdir_success) {
|
||||
lstat(".", &controlstat);
|
||||
lstat("..", &cwd_stat);
|
||||
if ( (filestat.st_dev != controlstat.st_dev) || (filestat.st_ino != controlstat.st_ino) ) {
|
||||
fprintf(stderr, "Race found! (directory %s became a link)\n", filename);
|
||||
} else {
|
||||
if ((dir = opendir (".")) != NULL) {
|
||||
(void) chmod(".", 0700); /* ignore permission errors */
|
||||
dir = opendir (".");
|
||||
}
|
||||
if (dir != NULL) {
|
||||
while ((dir_entry = readdir(dir)) != NULL)
|
||||
if (strcmp(dir_entry->d_name, ".") && strcmp(dir_entry->d_name, "..")) {
|
||||
if (verbose) printf("Wiping %s ", dir_entry->d_name);
|
||||
if ( (res = smash_it(dir_entry->d_name, mode)) > 0) {
|
||||
if (res == 3)
|
||||
fprintf(stderr,"File %s was raced, hence I won't wipe it.\n", dir_entry->d_name);
|
||||
else {
|
||||
fprintf(stderr,"Couldn't delete %s. ", dir_entry->d_name);
|
||||
perror("");
|
||||
}
|
||||
} else
|
||||
if (verbose) printf(" Done\n");
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
if(chdir(current_dir) != 0) {
|
||||
fprintf(stderr, "Error: Can't chdir to %s (aborting) - ", current_dir);
|
||||
perror("");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
lstat(current_dir, &controlstat);
|
||||
if ( (cwd_stat.st_dev != controlstat.st_dev) || (cwd_stat.st_ino != controlstat.st_ino) ) {
|
||||
fprintf(stderr, "Race found! (directory %s was exchanged or its your working directory)\n", current_dir);
|
||||
exit(1);
|
||||
}
|
||||
*/
|
||||
i_am_a_directory = 1;
|
||||
}
|
||||
}
|
||||
/* end of recursive function */
|
||||
|
||||
|
||||
if (S_ISREG(filestat.st_mode)) {
|
||||
|
||||
/* open the file for writing in sync. mode */
|
||||
if ((fd = open(filename, O_RDWR | O_LARGEFILE | slow)) < 0) {
|
||||
/* here again this has a race problem ... hmmm */
|
||||
/* make it writable for us if possible */
|
||||
(void) chmod(filename, 0600); /* ignore errors */
|
||||
if ((fd = open(filename, O_RDWR | O_LARGEFILE | slow)) < 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
fstat(fd, &controlstat);
|
||||
if ((filestat.st_dev != controlstat.st_dev) || (filestat.st_ino != controlstat.st_ino) || (! S_ISREG(controlstat.st_mode))) {
|
||||
close(fd);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (sdel_overwrite(mode, fd, 0, bufsize, filestat.st_size > 0 ? filestat.st_size : 1, zero) == 0)
|
||||
return sdel_unlink(filename, 0, 1, slow);
|
||||
} /* end IS_REG() */
|
||||
else {
|
||||
if (S_ISDIR(filestat.st_mode)) {
|
||||
if (i_am_a_directory == 0) {
|
||||
fprintf(stderr,"Warning: %s is a directory. I will not remove it, because the -r option is missing!\n", filename);
|
||||
return 0;
|
||||
} else
|
||||
return sdel_unlink(filename, 1, 0, slow);
|
||||
} else
|
||||
if (! S_ISDIR(filestat.st_mode)) {
|
||||
fprintf(stderr,"Warning: %s is not a regular file, rename/unlink only!", filename);
|
||||
if (! verbose)
|
||||
printf("\n");
|
||||
return sdel_unlink(filename, 0, 0, slow);
|
||||
}
|
||||
}
|
||||
|
||||
return 99; // not reached
|
||||
}
|
||||
|
||||
void cleanup(int signo) {
|
||||
fprintf(stderr,"Terminated by signal. Clean exit.\n");
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
FLUSH;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
int errors = 0;
|
||||
int dot = 0;
|
||||
int result;
|
||||
int secure = 2; /* Standard is now SECURE mode (38 overwrites) [since v2.0] */
|
||||
int loop;
|
||||
struct rlimit rlim;
|
||||
|
||||
prg = argv[0];
|
||||
if (argc < 2 || strncmp(argv[1], "-h", 2) == 0|| strncmp(argv[1], "--h", 3) == 0)
|
||||
help();
|
||||
|
||||
while (1) {
|
||||
result = getopt(argc, argv, "DdFfLlRrSsVvZz");
|
||||
if (result < 0) break;
|
||||
switch (result) {
|
||||
case 'd' :
|
||||
case 'D' : dot = 1;
|
||||
break;
|
||||
case 'F' :
|
||||
case 'f' : slow = 0;
|
||||
break;
|
||||
case 'L' :
|
||||
case 'l' : if (secure) secure--;
|
||||
break;
|
||||
case 'R' :
|
||||
case 'r' : recursive++;
|
||||
break;
|
||||
case 'S' :
|
||||
case 's' : secure++;
|
||||
break;
|
||||
case 'V' :
|
||||
case 'v' : verbose++;
|
||||
break;
|
||||
case 'Z' :
|
||||
case 'z' : zero++;
|
||||
break;
|
||||
default : help();
|
||||
}
|
||||
}
|
||||
loop = optind;
|
||||
if (loop == argc)
|
||||
help();
|
||||
|
||||
signal(SIGINT, cleanup);
|
||||
signal(SIGTERM, cleanup);
|
||||
signal(SIGHUP, cleanup);
|
||||
|
||||
sdel_init(slow);
|
||||
|
||||
if (verbose) {
|
||||
char type[15] = "random";
|
||||
if (zero) strcpy(type, "zero");
|
||||
switch (secure) {
|
||||
case 0 : printf("Wipe mode is insecure (one pass [%s])\n",type);
|
||||
break;
|
||||
case 1 : printf("Wipe mode is insecure (two passes [0xff/%s])\n",type);
|
||||
break;
|
||||
default: printf("Wipe mode is secure (38 special passes)\n");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef RLIM_INFINITY
|
||||
#ifdef RLIMIT_FSIZE
|
||||
rlim.rlim_cur = RLIM_INFINITY;
|
||||
rlim.rlim_max = RLIM_INFINITY;
|
||||
if (setrlimit(RLIMIT_FSIZE, &rlim) != 0)
|
||||
fprintf(stderr, "Warning: Could not reset ulimit for filesize.\n");
|
||||
#else
|
||||
fprintf(stderr, "Warning: Not compiled with support for resetting ulimit filesize.\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
while (loop < argc) {
|
||||
char rmfile[strlen(argv[loop]) + 1];
|
||||
strcpy(rmfile, argv[loop]);
|
||||
loop++;
|
||||
if (strcmp("/", rmfile) == 0) {
|
||||
fprintf(stderr,"Warning: Do you really want to remove the ROOT directory??\n");
|
||||
fprintf(stderr,"I'm giving you 5 seconds to abort ... press Control-C\n");
|
||||
sleep(6);
|
||||
fprintf(stderr,"Doing my evil work now, don't whimp later, you had been informed!\n");
|
||||
}
|
||||
if (dot)
|
||||
if ((strcmp(".", rmfile) == 0) || (strcmp("..", rmfile) == 0))
|
||||
continue;
|
||||
if (verbose)
|
||||
printf("Wiping %s ", rmfile);
|
||||
result = (int) smash_it(rmfile, secure);
|
||||
switch (result) {
|
||||
case 0 : if (verbose) printf(" Done\n");
|
||||
break;
|
||||
case 1 : fprintf(stderr, "Error: File %s - ", rmfile);
|
||||
perror("");
|
||||
break;
|
||||
case -1: break;
|
||||
case 3 : fprintf(stderr, "File %s was raced, hence I won't wipe it!\n", rmfile);
|
||||
break;
|
||||
default: fprintf(stderr, "Unknown error\n");
|
||||
}
|
||||
if (result)
|
||||
errors++;
|
||||
}
|
||||
|
||||
sdel_finnish();
|
||||
|
||||
if (errors)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
.\" This definition swiped from the gcc(1) man page
|
||||
.de Sp
|
||||
.if n .sp
|
||||
.if t .sp 0.4
|
||||
..
|
||||
.TH SSWAP 1
|
||||
|
||||
.SH NAME
|
||||
sswap \- secure swap wiper (secure_deletion toolkit)
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B sswap [-f] [-l] [-l] [-v] [-z] swapdevice
|
||||
|
||||
.SH DESCRIPTION
|
||||
.I sswap
|
||||
is designed to delete data which may lie still on your swapspace
|
||||
in a secure manner which can not be recovered by thiefs, law enforcement
|
||||
or other threats.
|
||||
The wipe algorythm is based on the paper "Secure Deletion of Data from
|
||||
Magnetic and Solid-State Memory" presented at the 6th Usenix Security
|
||||
Symposium by Peter Gutmann, one of the leading civilian cryptographers.
|
||||
.PP
|
||||
The
|
||||
.I secure data deletion
|
||||
process of sswap goes like this:
|
||||
.PP
|
||||
.TP
|
||||
.B *
|
||||
1 pass with 0xff
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.TP
|
||||
.B *
|
||||
27 passes with special values defined by Peter Gutmann.
|
||||
.TP
|
||||
.B *
|
||||
5 random passes. /dev/urandom is used for a secure RNG if available.
|
||||
.PP
|
||||
|
||||
.SH COMMANDLINE OPTIONS
|
||||
.PP
|
||||
.TP
|
||||
.B \-f
|
||||
fast (and insecure mode): no /dev/urandom, no synchronize mode.
|
||||
.TP
|
||||
.B \-l
|
||||
lessens the security. Only two passes are written: one mode with 0xff and
|
||||
a final mode with random values.
|
||||
.TP
|
||||
.B \-l
|
||||
-l for a second time lessons the security even more: only one pass with
|
||||
random values is written.
|
||||
.TP
|
||||
.B \-v
|
||||
verbose mode
|
||||
.TP
|
||||
.B \-z
|
||||
wipes the last write with zeros instead of random data
|
||||
.PP
|
||||
|
||||
.SH BEWARE
|
||||
.TP
|
||||
.B swapoff
|
||||
unmount your swapspace before using this tool! Otherwise your system might
|
||||
crash!
|
||||
.TP
|
||||
.B BETA!
|
||||
.I sswap
|
||||
is still beta. It was only tested on Linux but on this system it performed
|
||||
it's work all of the time.
|
||||
|
||||
.PP
|
||||
.SH BUGS
|
||||
No bugs. There was never a bug in the secure_deletion package (in contrast
|
||||
to my other tools, whew, good luck ;-)
|
||||
Send me any that you find. Patches are nice too :)
|
||||
|
||||
.SH AUTHOR
|
||||
.Sp
|
||||
van Hauser / THC
|
||||
.I <vh@thc.org>
|
||||
|
||||
.SH DISTRIBUTION
|
||||
The newest version of the
|
||||
.I secure_deletion package
|
||||
can be obtained from
|
||||
.I http://www.thc.org
|
||||
.Sp
|
||||
.I sswap
|
||||
and the
|
||||
.I secure_deletion package
|
||||
is (C) 1997-2003 by van Hauser / THC (vh@thc.org)
|
||||
.Sp
|
||||
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; Version 2.
|
||||
.Sp
|
||||
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.
|
||||
|
||||
.SH SEE ALSO
|
||||
.I srm
|
||||
(1),
|
||||
.I sfill
|
||||
(1),
|
||||
.I smem
|
||||
(1)
|
||||
@@ -0,0 +1,160 @@
|
||||
/* Secure SWAP cleaner - by van Hauser / [THC], vh@thc.org
|
||||
*
|
||||
* Note that this program is beta. It was tested with linux, but I can't
|
||||
* tell for other platforms. Read the statement at #define SWAP_PAGESIZE
|
||||
* on how to use this program on other unix machines.
|
||||
*
|
||||
* of course: you have to turn of the swapspace before using this program !
|
||||
*
|
||||
* Secure SWAP overwrites all data on your swap device.
|
||||
* Standard mode is a real security wipe for 38 times, flushing
|
||||
* the caches after every write. The wipe technique was proposed by Peter
|
||||
* Gutmann at Usenix '96 and includes 10 random overwrites plus 28 special
|
||||
* defined characters. Take a look at the paper of him, it's really worth
|
||||
* your time.
|
||||
* The option -l overwrites two times the data. (0xff + random)
|
||||
* The option -ll overwrites the data once. (random)
|
||||
*
|
||||
* Read the manual for limitations.
|
||||
* Compiles clean on OpenBSD, Linux, Solaris and AIX
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <strings.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sdel.h"
|
||||
|
||||
/* SWAP_PAGESIZE is an important variable. You have to set this
|
||||
* to your header length of your swapdevice. For Linux this is 4096,
|
||||
* I don't know for the other OSs. To be sure, set this to 0 and
|
||||
* recreate your swapspace afterwards (for linux: mkswap /dev/swapdevice)
|
||||
*/
|
||||
#define SWAP_PAGESIZE 4096
|
||||
#ifdef BLOCKSIZE
|
||||
#undef BLOCKSIZE
|
||||
#endif
|
||||
#define BLOCKSIZE 65535
|
||||
|
||||
int fd;
|
||||
int slow = O_SYNC;
|
||||
int zero = 0;
|
||||
|
||||
void help() {
|
||||
printf("sswap %s (c) 1997-2003 by %s <%s>\n\n", VERSION, AUTHOR, EMAIL);
|
||||
printf("Syntax: %s [-flvz] [-j start] /dev/of_swap_device\n\n", prg);
|
||||
printf("Options:\n");
|
||||
printf("\t-f fast (and insecure mode): no /dev/urandom, no synchronize mode.\n");
|
||||
printf("\t-j jump over the first number of bytes when wiping. (default: %d)\n", SWAP_PAGESIZE);
|
||||
printf("\t-l lessens the security (use twice for total insecure mode).\n");
|
||||
printf("\t-v is verbose mode.\n");
|
||||
printf("\t-z last wipe writes zeros instead of random data.\n");
|
||||
printf("\nsswap does a secure overwrite of the swap space.\n");
|
||||
printf("Default is secure mode (38 writes).\n");
|
||||
printf("Updates can be found at %s\n", WEB);
|
||||
printf("\nNOTE: You must disable the swapspace before using this program!\007\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
fprintf(stderr,"\nTerminated by signal. Clean exit.\n");
|
||||
close(fd);
|
||||
sync();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
int secure = 2;
|
||||
int result;
|
||||
int mode;
|
||||
unsigned long start = SWAP_PAGESIZE;
|
||||
struct stat stats;
|
||||
char *filename;
|
||||
|
||||
prg = argv[0];
|
||||
if (argc == 1 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--h", 3) == 0)
|
||||
help();
|
||||
|
||||
while (1) {
|
||||
result = getopt(argc, argv, "FfJ:j:LlSsVvZz");
|
||||
if (result<0) break;
|
||||
switch (result) {
|
||||
case 'F' :
|
||||
case 'f' : slow = 0;
|
||||
break;
|
||||
case 'J' :
|
||||
case 'j' : start = atol(optarg);
|
||||
if (start < 0 || start > 65535) {
|
||||
fprintf(stderr, "Error: The -j option must be set between 0 and 65535!\n");
|
||||
exit(-1);
|
||||
}
|
||||
break;
|
||||
case 'L' :
|
||||
case 'l' : if (secure) secure--;
|
||||
break;
|
||||
case 'S' :
|
||||
case 's' : secure++;
|
||||
break;
|
||||
case 'V' :
|
||||
case 'v' : verbose++;
|
||||
break;
|
||||
case 'Z' :
|
||||
case 'z' : zero++;
|
||||
break;
|
||||
default : help();
|
||||
}
|
||||
}
|
||||
|
||||
if ((optind+1) != argc)
|
||||
help();
|
||||
|
||||
signal(SIGINT, cleanup);
|
||||
signal(SIGTERM, cleanup);
|
||||
signal(SIGHUP, cleanup);
|
||||
|
||||
filename = argv[optind];
|
||||
mode = secure;
|
||||
|
||||
if ((fd = open (filename, O_RDWR | O_LARGEFILE | slow)) < 0) {
|
||||
fprintf(stderr, "Error: Can't open %s for writing.", filename);
|
||||
perror("");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fstat(fd, &stats);
|
||||
if (!S_ISBLK(stats.st_mode)) {
|
||||
fprintf(stderr, "Error: Target is not a block device - %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
char type[15] = "random";
|
||||
if (zero) strcpy(type, "zero");
|
||||
switch (mode) {
|
||||
case 0 : printf("Wipe mode is insecure (one pass [%s])\n",type);
|
||||
break;
|
||||
case 1 : printf("Wipe mode is insecure (two passes [0xff/%s])\n",type);
|
||||
break;
|
||||
default: printf("Wipe mode is secure (38 special passes)\n");
|
||||
}
|
||||
printf("Writing to device %s: ", filename);
|
||||
}
|
||||
|
||||
sdel_init(slow);
|
||||
|
||||
if (sdel_overwrite(mode, fd, start, BLOCKSIZE, 0, zero) == 0)
|
||||
if (verbose)
|
||||
printf(" done\n");
|
||||
|
||||
sdel_finnish();
|
||||
|
||||
/* thats all */
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# THE CLEANER SCRIPT
|
||||
# Part of the secure_data_deletion toolkit by van Hauser / THC
|
||||
# Run at your own risk. Tested on Linux only.
|
||||
#
|
||||
# Run this to wipe your system as most as possible with automatic stuff.
|
||||
# You should run this in the STOP runlevels 2 and 3.
|
||||
#
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
# Please configure the following variables:
|
||||
#
|
||||
#
|
||||
# WIPE_MODE: 1-3
|
||||
# 1: highly secure mode (38 wipes)
|
||||
# 2: insecure mode (2 wipes)
|
||||
# 3: highly insecure mode (1 wipe)
|
||||
WIPE_MODE=3
|
||||
#
|
||||
#
|
||||
# WIPE_FAST: yes/no
|
||||
# yes: dont use a secure random number generator, less secure
|
||||
# no: use a secure random number generator, secure
|
||||
WIPE_FAST=yes
|
||||
#
|
||||
#
|
||||
# WIPE_VERBOSE: yes/no
|
||||
# yes: write verbose messages
|
||||
# no: only write if error/warnings occur
|
||||
WIPE_VERBOSE=yes
|
||||
#
|
||||
#
|
||||
# WIPE_DIRECTORIES: directories you want to wipe completely all files and
|
||||
# subdirectories from. Usually /tmp, /usr/tmp and /var/tmp.
|
||||
WIPE_DIRECTORIES="/tmp /usr/tmp /var/tmp"
|
||||
#
|
||||
# WIPE_USER_FILES: files you want to wipe from user directories. Usually
|
||||
# .*history*, .netscape/cache/*, .netscape/history*,
|
||||
# .netscape/cookies, tmp/*, *~ and core
|
||||
WIPE_USER_FILES=".*history* .netscape/cache/ .netscape/history* \
|
||||
.netscape/cookies .lynx_cookies tmp/* *~ .gqview_thmb/ dead.letter core"
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
# Preparation Phase
|
||||
#
|
||||
test "$WIPE_MODE" -gt 0 -a "$WIPE_MODE" -lt 4 || {
|
||||
echo "WIPE_MODE must be a value between 1 and 3."
|
||||
exit 1
|
||||
}
|
||||
test "$WIPE_FAST" = yes -o "$WIPE_FAST" = "no" || {
|
||||
echo "WIPE_FAST must be either yes or no."
|
||||
exit 1
|
||||
}
|
||||
test "$WIPE_VERBOSE" = yes -o "$WIPE_VERBOSE" = "no" || {
|
||||
echo "WIPE_VERBOSE must be either yes or no."
|
||||
exit 1
|
||||
}
|
||||
MODE=""
|
||||
test "$WIPE_MODE" -eq 2 && MODE="-l"
|
||||
test "$WIPE_MODE" -eq 3 && MODE="-ll"
|
||||
FAST=""
|
||||
test "$WIPE_FAST" = yes && FAST="-f"
|
||||
VERBOSE=""
|
||||
test "$WIPE_VERBOSE" = yes && VERBOSE="-v"
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
#
|
||||
# Starting the wiping process
|
||||
#
|
||||
|
||||
# Wipe directories
|
||||
test -z "$VERBOSE" || echo "STARTING THE CLEANER."
|
||||
test -z "$VERBOSE" || echo "CLEANER: Wiping directory contents"
|
||||
for i in $WIPE_DIRECTORIES; do
|
||||
test -z "$i" -o "$i" = "." -o "$i" = ".." -o "$i" = "/" || {
|
||||
test -z "$VERBOSE" || echo " $i"
|
||||
cd "$i" && srm $MODE $FAST -d -r -- .* *
|
||||
}
|
||||
done
|
||||
|
||||
# Wipe files
|
||||
test -z "$VERBOSE" || echo "CLEANER: Wiping user files"
|
||||
awk -F: '{ print $1 " " $6 }' /etc/passwd |
|
||||
while read user homedir; do
|
||||
test "$homedir" = "" -o "$homedir" = "." -o "$homedir" = ".." || {
|
||||
cd "$homedir" && {
|
||||
test -z "$VERBOSE" || echo " $user"
|
||||
for j in $WIPE_USER_FILES; do
|
||||
test -z "$j" || {
|
||||
test -L "$j" || {
|
||||
test -e "$j" && srm $MODE $FAST -d -r -- $j
|
||||
# test -e "$j" && "i would wipe: $j"
|
||||
}
|
||||
}
|
||||
done
|
||||
}
|
||||
}
|
||||
done
|
||||
|
||||
# Wipe free space and inodes
|
||||
test -z "$VERBOSE" || echo "CLEANER: Wiping free space and inodes on filesystems"
|
||||
for i in `mount|grep -E '^/dev/.* type ext'|awk '{print$3}'`; do
|
||||
test -z "$VERBOSE" || echo " $i"
|
||||
test -z "$i" || sfill $MODE $FAST "$i"
|
||||
done
|
||||
|
||||
# Now the swap space:
|
||||
test -z "$VERBOSE" || echo "CLEANER: Wiping swap space"
|
||||
#ACTIVE=`swapoff -s|grep ^/dev/|awk '{print$1}'`
|
||||
swapoff -a
|
||||
for i in `(grep -w swap /etc/fstab|awk '{print$1}';echo "$ACTIVE";)|sort -u`; do
|
||||
test -z "$VERBOSE" || echo " $i"
|
||||
test -z "$i" || sswap $MODE $FAST "$i"
|
||||
done
|
||||
|
||||
# Finally the memory:
|
||||
test -z "$VERBOSE" || echo "CLEANER: Wiping the memory"
|
||||
smem $MODE $FAST
|
||||
#
|
||||
|
||||
swapon -a
|
||||
|
||||
# FINNISHED!
|
||||
test -z "$VERBOSE" || echo "THE CLEANER FINNISHED."
|
||||
@@ -1,2 +1,61 @@
|
||||
# hiddencrypto
|
||||
|
||||
# hiddencrypto
|
||||
Silly lil script for using [scrypt](https://github.com/Tarsnap/scrypt), [secure-delete (srm)](https://github.com/BlackArch/secure-delete), and tar to open and close an encrypted (scrypt) and compressed (bz2) and shred (srm) any lingering data immediately.
|
||||
|
||||
## Textwall about the frickin thing
|
||||
Encryption MY way!
|
||||
I was totally fucked off by the normie file encryption utilities like Veracrypt,. Cryptomator and `openssl enc` because in practice they have a couple absolutely glaring flaws.
|
||||
|
||||
For one, they are STILL using PMDKF2 as the KDF (Key Derivation Function, the algo that deterministically generates the 256-bit key from a passphrase) and the simple truth is that PBDKF2 is criminally outdated and no ever increasing number of iterations into the millions and millions are ever gonna change that.
|
||||
So, I selected the gigachad KDF, Scrypt to generate the 256-bit key. It features appx. 10 billion times the hardware cost to crack vs `openssl enc` it has appx. 20,000 times greater hardware cost to crack vs PBDK2 with any number of iterations, and appx. 4,000 times the hardware cost to crack vs Bcrypt, the algo used to hash Linux passwords.
|
||||
Scrypt is stable and solid, and has passed countless rounds of cryptanalysis and revision by Cypherpunks and the wider cryptography community, so it should be quite cryptographically secure.
|
||||
|
||||
The other glaring issue that the normie cryptography utilities had was the fact that when files are moved to the volume, there is no shredding of the "ghost" file at the location it camer from, and in some cases, even left data traes on the disk without securely shredding them to clean up.
|
||||
To that end, I'm using the secure-delete package to secure wipe any temporary or ghost bytes off the record.
|
||||
srm is used to delete files and directories immediately upon compl,eting the next step successfully.
|
||||
smem is used to wipe unallocated RAM to ensure that no remaning traces of data are left in memory even with a sophisticated memory forensics or cold boot attack.
|
||||
//todo: There will also have an option to wide empty space on a given disk for convenience.
|
||||
//todo: A feature that shreds the first 1024 bytes of the encrypted archive so that the data is completely nuked and unrecoverable even with the passphrase. The feature should be easily integrated into other systems such that a nuke order can be executed from any custom event or trigger e.g. Alexa command, key combination on another comptuer, time based dead man's switch, etc.
|
||||
|
||||
## Back Up Your Shit
|
||||
* This script is probably as unstable as I am and will probably end up nuking your files
|
||||
* If you lose your passphrase or type it in wrong twice on encryption, your data has gone bye bye
|
||||
* For real, back up your shit
|
||||
* Do not trust me or my code
|
||||
|
||||
## Important Details
|
||||
* Each time you encrypt the directory, it will use a brand new passphrase that you input. You can still use the old one, but it is set each time to whatever you enter twice regardless of the previous passphrase
|
||||
* Use a [secure passphrase](assets/how-to-create-a-secure-passphrase-2017-08-10_HQP.pdf) and DO NOT SAVE ON COMPUTER OR PASSSWORD MANAGER! Only save your passphrase on **PHYSICAL PAPER**
|
||||
* **Back Up Your Shit!** This is a completely unforgiving script when it comes to setting the password wrong
|
||||
* When creating encrypted backups, be certain to use a seperate, completely dissimilar passphrase for it. Store this passphrase on a seperate piece of paper, stored seperately
|
||||
* **Test Your Backups** Make completely sure they work and that you a precise and accurate passphrase for them
|
||||
* If your system has automatic backuops, RAID, cloud storage uplaods, or any other type of redundancy system in place, you should exclude the hiddebncrypto directory from it. Otherwise, partial or even data leaking data could be copied or even uploaded
|
||||
* **BE AWARE** When moving files from unencrypted drives to the encrypted arcive, **the original files may be recoverable from the original location** even if they are not visible. It is a best practice to shred empty space on that disk afterwords to ensure the orignal data is not forensically recoverable
|
||||
* Best practice is to disable networking when using hiddencrypto
|
||||
|
||||
## Usage
|
||||
To install:
|
||||
```
|
||||
cd ~
|
||||
git clone https://github.com/PrincessPi3/hiddencrypto.git
|
||||
cd hiddencrypto
|
||||
sudo sh hiddencrypto.sh install
|
||||
```
|
||||
|
||||
To encrypt:
|
||||
`sh hiddencrypto.sh enc`
|
||||
|
||||
To decrypt:
|
||||
`sh hiddencrypto.sh dec`
|
||||
|
||||
## License
|
||||
Distributed under the [WTFPL Version 2](http://www.wtfpl.net/) [](http://www.wtfpl.net/)
|
||||
See [assets/COPYING.txt](assets/COPYING.txt) for text
|
||||
|
||||
|
||||
```
|
||||
Todo:
|
||||
|
||||
Potential memory key leaks
|
||||
Potential OS key leaks
|
||||
Potential side-channel attacks
|
||||
```
|
||||
@@ -0,0 +1,4 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
# fail on error
|
||||
set -e
|
||||
|
||||
dir_to_encrypt=./to_encrypt
|
||||
encrypted_archive_name=./.volume.bin
|
||||
|
||||
encrypted_volume_name=./.encrypted_volume.tar.bz2
|
||||
|
||||
encrypty(){
|
||||
echo "Compressing Directory..."
|
||||
tar cfj $encrypted_volume_name $dir_to_encrypt
|
||||
|
||||
echo "Sucesfully Compressed, Shredding Directory..."
|
||||
srm -rz $dir_to_encrypt
|
||||
|
||||
echo "Successfully Shredded Directory, Encrypting. Please Input Passphrase..."
|
||||
scrypt enc $encrypted_volume_name $encrypted_archive_name
|
||||
|
||||
echo "Successfully Encrypted, Shredding Archive..."
|
||||
srm -rz $encrypted_volume_name
|
||||
|
||||
echo "Wiping deallocated RAM..."
|
||||
sudo smem -ll # -ll is a single overwrite mode with 0xFF, single mode used for speed
|
||||
|
||||
echo "Success: Encryption Done"
|
||||
}
|
||||
|
||||
decrypty(){
|
||||
echo "Starting..."
|
||||
|
||||
echo "Decrypting. Please Input Passphrase..."
|
||||
scrypt dec $encrypted_archive_name $encrypted_volume_name
|
||||
|
||||
echo "Successfully Decrytped, Shredding Encrypted Archive..."
|
||||
srm -rz $encrypted_archive_name
|
||||
|
||||
echo "Successfully Shredded Encrypted Archive, Decompressing..."
|
||||
tar xfj $encrypted_volume_name
|
||||
|
||||
echo "Successfully Decompressed Decrypted Archive, Shredding Decrypted Archive..."
|
||||
srm -rz $encrypted_volume_name
|
||||
|
||||
echo "Wiping deallocated RAM..."
|
||||
sudo smem -ll # -ll is a single overwrite mode with 0xFF, single mode used for speed
|
||||
|
||||
echo "Success: Done"
|
||||
}
|
||||
|
||||
if [ "$1" = "enc" ]; then
|
||||
encrypty
|
||||
elif [ "$1" = "dec" ]; then
|
||||
decrypty
|
||||
elif [ $1 = "install" ]; then
|
||||
if ! [ -f "$(command -v scrypt)" ] && [ -f "$(command -v tar)" ] && [ -f "$(command -v make)" ]; then
|
||||
echo "Needed Applications Not Found, Installing..."
|
||||
sudo apt install scrypt secure-delete tar build-essential
|
||||
echo "Success: Installed"
|
||||
fi
|
||||
|
||||
if ! [ -f "./.secure-delete/smem" ]; then
|
||||
echo "Building Edited secure-delete Utilities..."
|
||||
cd ./.secure-delete
|
||||
sudo make
|
||||
|
||||
echo "Installing Edited secure-delete Utiliies..."
|
||||
sudo make install
|
||||
|
||||
echo "Cleaning Up From Build..."
|
||||
cd ..
|
||||
sudo srm -rz ./.secure-delete
|
||||
|
||||
echo "Success: secure-delete Installed"
|
||||
fi
|
||||
|
||||
if ! [ -d $dir_to_encrypt ]; then
|
||||
echo "$dir_to_encrypt Not Found, Creating..."
|
||||
mkdir $dir_to_encrypt
|
||||
fi
|
||||
|
||||
echo "Success: Ready to use"
|
||||
else
|
||||
echo "Usage:\nEncrypt:\n\tsh hiddencrypto.sh enc\nDecrypt:\n\tsh hiddencrypto.sh dec\nInstall:\n\tsh hiddencrypto.sh install"
|
||||
fi
|
||||
Reference in New Issue
Block a user