--- UPDATED with better console stuff and now using the crypto random number generator.
I know that some of you have found yourself in that situation that requires you to delete something from your hard drive permanently, thus rendering your data unrecoverable.
Well, there isn't a good way to do that through C# without some tomfoolery... so I hereby present you with
SuperDelete. This code will permanently delete whatever file you pass in, overwriting the existing data with cryptographically random numbers a specified number of times before deleting the file. This renders the previously existing data pretty much useless to anyone.
As long as data is being flushed to the drive after each file write (hence the foreach over the FileStream), and your system doesn't have some sort of advanced write-caching in place that will cache data over multiple file opens and closes, your data will be as good as dead once this code is finished with it.
The recommended overwrite of 10 times is to cover the nominal servo-positioning errors that occur in all hard drives, however you can push this up to whatever value you want to make yourself feel secure.
I also recommend that you read this article on data storage and recovery:
http://wipe.sourceforge.net/secure_del.html.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace SuperDelete
{
class Program
{
static byte[] buffer = new byte[32768];
static void Main(string[] args)
{
Console.WriteLine("Usage: SuperDelete.exe <filename> <number of wipes>");
Console.WriteLine("Example: SuperDelete.exe \"C:\\mySecrets.txt\" 10");
try
{
Console.WriteLine("");
Console.WriteLine("Are you sure you want to SuperDelete the file {0}? (Y/N)", args[0]);
if (Console.ReadKey().Key == ConsoleKey.Y)
SuperDeleteFile(args[0], Convert.ToInt32(args[1]));
}
catch (Exception e)
{
Console.WriteLine("Failed to super delete :(");
Console.WriteLine(e.Message);
}
}
public static void SuperDeleteFile(string fileName, int passes)
{
Console.WriteLine("");
Console.WriteLine("Deleting...");
int cursorTop = Console.CursorTop;
int cursorLeft = Console.CursorLeft;
for (int i = 0; i < passes; i++)
{
using (FileStream fileToOverwrite = File.Open(fileName, FileMode.Open, FileAccess.Write, FileShare.None))
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(new CspParameters(24));
rng.GetBytes(buffer);
long bytesToWrite = fileToOverwrite.Length;
long originalFileSize = fileToOverwrite.Length;
while (bytesToWrite > 0)
{
Console.CursorLeft = cursorLeft;
Console.CursorTop = cursorTop;
string messageOne = string.Format("Pass {0}, wiping bytes {1} - {2} of {3}. ", i, originalFileSize - bytesToWrite, (originalFileSize - bytesToWrite) + buffer.Length, originalFileSize);
string messageTwo = string.Format("This pass has %{0} left to complete.", Convert.ToInt64((Convert.ToDouble(bytesToWrite) / Convert.ToDouble(originalFileSize)) * 100));
Console.WriteLine(PadToLength(messageOne, Console.BufferWidth));
Console.WriteLine(PadToLength(messageTwo, Console.BufferWidth));
fileToOverwrite.Write(buffer, 0, buffer.Length);
bytesToWrite -= buffer.Length;
}
}
}
File.Delete(fileName);
}
static string PadToLength(string original, int length)
{
if (original.Length >= length)
return original;
StringBuilder sb = new StringBuilder(original);
for (int i = original.Length +1; i < length; i++)
{
sb.Append(" ");
}
return sb.ToString();
}
}
}
For the complete program, including the disabling of write-caching, please purchase my Super Delete application.