Subject: "Secure" harddisk eraser?
To: None <netbsd-users@netbsd.org>
From: Florian Stoehr <netbsd@wolfnode.de>
List: netbsd-users
Date: 02/06/2005 13:22:38
Hi all,

I didn't know about any existing eraser tool under NetBSD,
so I played around and wrote my own, capable of erasing
single partitions (or whole disks of course). Now I have some 
questions about this task.

I implemented a 35-pass pattern eraser, like Gutmann requested
in

http://www.linux-kurser.dk/secure_del_peter_gutmann.html

The goal of this program is not to stop any freak with special
controller or oscilloscope - 3 times with random data might be
enough here - but to raise time needed to restore data or
make it too expensive for government authorities (at least
if you're not involved in serious crime).

Note that the 35 pass is useless since not all patterns are
needed for every hardware encoding mechanism - some random
writes are all you can do for (E)PRML drives.

Some questins following:
- How secure is what Gutmann says? Will it effectively make
recovery that hard/expensive (note that the paper is from 1996!)
- Any other ideas about "secure" erasing magnetical media by software?
- What about random(3)? How "random" is random()? The current code
in my program is bad since it will start with the same sequence
every time - how to do better?

Notes about the code:
- Need better random data
- Do not use the same 64*3 block for random data
- Add encoding-based pass selection (no 35-pass at all!)

Thanks
Florian

Code follows:

/* $Id: neb-wipe.c,v 1.2 2005/02/06 12:19:51 cvs Exp $ */

/*
  * NEB-WIPE - Secure harddisk eraser (Gutmann)
  * Secure 35-pass harddisk erasing tool
  *
  * Written by Florian Stoehr <ich@florian-stoehr.de>
  */

#include <sys/param.h>

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

#define BSIZE 64*1024*3

void CreateBufferRandom(void);
void CreateBuffer(unsigned char, unsigned char, unsigned char);
void DiskIO(void);
void WritePassRandom(const char *);
void WritePass(const char *, unsigned char, unsigned char, unsigned char);

unsigned char buffer[BSIZE];
char s_Device[MAXPATHLEN+1];
int i_FD;

/*
  * Create a buffer full of random data
  */
void
CreateBufferRandom(void)
{
 	long rander;
 	int i;
 	unsigned char *rptr;

 	for (i = 0; i < BSIZE / 3; i++) {
 		rander = random();
 		rptr = (unsigned char *)&rander;

 		*(buffer + (i * 3)) = *rptr++;
 		*(buffer + (i * 3) + 1) = *rptr++;
 		*(buffer + (i * 3) + 2) = *rptr++;
 	}
}

/*
  * Create a non-random overwrite pattern
  */
void
CreateBuffer(unsigned char m1, unsigned char m2, unsigned char m3)
{
 	int i;

 	for (i = 0; i < BSIZE / 3; i++) {
 		*(buffer + (i * 3)) = m1;
 		*(buffer + (i * 3) + 1) = m2;
 		*(buffer + (i * 3) + 2) = m3;
 	}
}

/*
  * Actually perform the I/O
  */
void
DiskIO(void)
{
 	lseek(i_FD, 0, SEEK_SET);

 	for (;;) {
 		if (write(i_FD, buffer, BSIZE) != BSIZE)
 			break;
 	}
}

/*
  * Invoke one pass of random writing
  */
void
WritePassRandom(const char *s)
{
 	printf("%s\n", s);

 	CreateBufferRandom();
 	DiskIO();
}

/*
  * Invoke one pass of pattern writing
  */
void
WritePass(const char *s, unsigned char m1, unsigned char m2, unsigned char 
m3)
{
 	printf("%s\n", s);

 	CreateBuffer(m1, m2, m3);
 	DiskIO();
}

/*
  * neb-wipe: Programm to wipe off harddisk partitions in a secure manner
  */
int
main(int argc, char **argv)
{
 	setprogname(argv[0]);

 	if (argc < 2)
 	{
 		printf("Usage is: neb-wipe device\n"\
 		       "          where device is the desired partition, 
e.g. \"sd0a\"\n");

 		exit(EXIT_FAILURE);
 	}

 	/* Data setup */
 	i_FD = opendisk(argv[1], O_WRONLY, s_Device, MAXPATHLEN, 0);

 	if (i_FD == -1)	{
 		printf("ERROR opening device. Make sure you are root.\n");

 		exit(EXIT_FAILURE);
 	}

 	/* Pass sequences */
 	WritePassRandom("01/35: Random seq 1");
 	WritePassRandom("02/35: Random seq 2");
 	WritePassRandom("03/35: Random seq 3");
 	WritePassRandom("04/35: Random seq 4");
 	WritePass("05/35: Pattern seq 1", 0x55, 0x55, 0x55);
 	WritePass("06/35: Pattern seq 2", 0xAA, 0xAA, 0xAA);
 	WritePass("07/35: Pattern seq 3", 0x92, 0x49, 0x24);
 	WritePass("08/35: Pattern seq 4", 0x49, 0x24, 0x92);
 	WritePass("09/35: Pattern seq 5", 0x24, 0x92, 0x49);
 	WritePass("10/35: Pattern seq 6", 0x00, 0x00, 0x00);
 	WritePass("11/35: Pattern seq 7", 0x11, 0x11, 0x11);
 	WritePass("12/35: Pattern seq 8", 0x22, 0x22, 0x22);
 	WritePass("13/35: Pattern seq 9", 0x33, 0x33, 0x33);
 	WritePass("14/35: Pattern seq 10", 0x44, 0x44, 0x44);
 	WritePass("15/35: Pattern seq 11", 0x55, 0x55, 0x55);
 	WritePass("16/35: Pattern seq 12", 0x66, 0x66, 0x66);
 	WritePass("17/35: Pattern seq 13", 0x77, 0x77, 0x77);
 	WritePass("18/35: Pattern seq 14", 0x88, 0x88, 0x88);
 	WritePass("19/35: Pattern seq 15", 0x99, 0x99, 0x99);
 	WritePass("20/35: Pattern seq 16", 0xAA, 0xAA, 0xAA);
 	WritePass("21/35: Pattern seq 17", 0xBB, 0xBB, 0xBB);
 	WritePass("22/35: Pattern seq 18", 0xCC, 0xCC, 0xCC);
 	WritePass("23/35: Pattern seq 19", 0xDD, 0xDD, 0xDD);
 	WritePass("24/35: Pattern seq 20", 0xEE, 0xEE, 0xEE);
 	WritePass("25/35: Pattern seq 21", 0xFF, 0xFF, 0xFF);
 	WritePass("26/35: Pattern seq 22", 0x92, 0x49, 0x24);
 	WritePass("27/35: Pattern seq 23", 0x49, 0x24, 0x92);
 	WritePass("28/35: Pattern seq 24", 0x24, 0x92, 0x49);
 	WritePass("29/35: Pattern seq 25", 0x6D, 0xB6, 0xDB);
 	WritePass("30/35: Pattern seq 26", 0xB6, 0xDB, 0x6D);
 	WritePass("31/35: Pattern seq 27", 0xDB, 0x6D, 0xB6);
 	WritePassRandom("32/35: Random seq 5");
 	WritePassRandom("33/35: Random seq 6");
 	WritePassRandom("34/35: Random seq 7");
 	WritePassRandom("35/35: Random seq 8");

 	close(i_FD);

 	exit(EXIT_SUCCESS);
}