Home | @unixist | unixist@freenode

>: Poor Man’s Shred


I recently found myself in a situation that called for securely wiping files from disk. The problem was on a very large number of hosts where I could not bring in outside tools and could not depend on the availability of shred or a shred-like tool. So I wrote something to do the job in shell script. I don’t think it sucks too badly and it only requires a POSIX-ish shell and a source of entropy, such as /dev/urandom.

The idea is simple. Overwrite a file a given number of times, each time with a different pattern (preferably random pattern). This is not a perfect deletion mechanism and it hasn’t been tested on solid state drives, but it is effective against several types of data recovery methods and may be your only option if you don’t have physical access to the disk.

See this writeup for a good overview of secure data deletion from magnetic and solid-state memory. Make sure you check out its Epilogues.

Configurables:

$ops: the number of overwrite passes.
$block_size: the filesystem’s block size. Writes go faster if you use the correct block size.
$r: the source of entropy

Once you’ve configured the right settings, execute with $./shred.sh <filename>

 f="$1"
 r="/dev/urandom"
 ops=10
 block_size=512
 
 [ -z "$f" -o ! -f "$f" ] && echo "Specify a valid filename" && exit 1
 echo -n "Continue shredding $f (y/n)? "
 read ans
 [ "$ans" != "y" -a "$ans" != "Y" ] && exit 1
 
 file_size=$(stat -c %s "$f")
 count=$(expr "$file_size" / "$block_size")
 mod=$(expr "$file_size" % "$block_size")
 i=0
 while [ $i -le $ops ]; do
  /bin/dd if="$r" of="$f" count="$count" bs="$block_size"
  if [ "$mod" -ne 0 ]; then # If file length != factor of $block_size
     /bin/dd oflag=append conv=fdatasync,notrunc if=/dev/urandom of="$f" count=1 bs="$mod"
  fi
  ((i++))
 done
 
 # Now that the file is trashed, unlink inode if there are no hard links to this file
 if [ $(stat -c %h "$f") -eq 1 ]; then
  /bin/rm "$f" && /bin/echo "File successfully deleted"
  exit 0
 else
  /bin/echo "File trashed but not unlinked due to hard link found (inode=$(stat -c %i $f))"
  exit 1
 fi