Click here to Skip to main content
Licence CPOL
First Posted 7 Jan 2008
Views 26,392
Downloads 574
Bookmarked 54 times

Securely Delete a File using .NET

By | 14 Jan 2008 | Article
How to securely delete a file using .NET

Introduction

This is an attempt to make it a little more secure to delete files using C#. Let's face it: using File.Delete doesn't really delete the file; it just makes the OS think that the file doesn't exist. The space on the disc that the file occupied is marked as free and available for writing, but the file's data is not removed and can be recovered quite easily. The file is not gone until the space it occupied is overwritten, preferably several times.

I have put together a simple class that can be used to accomplish the procedure of writing garbage data to the file before deleting it. To take it a step further, I truncate the file to 0 bytes and change the file-dates. However, the step to change the file dates only seems to work on FAT 16/32 and not NTFS. After running several tests with Ontrack EasyRecovery, PC Inspector File Recovery and GetDataBack, I could not recover any of the files. I even ran Disk Investigator after deleting a text-file, checking the individual clusters, and I couldn't get a single word back from the file.

Background

The background to this project is simple. After using file-wipers/shredders for years now, I wanted to see what could be accomplished with .NET.

Using the Code

There is only one method that you need to call, namely WipeFile and the code is as shown below. So, all you really have to do is call WipeFile and supply the full path of the file to be deleted, as well as the number of times you want to overwrite it.

public void WipeFile(string filename, int timesToWrite)
{
    try
    {
        if (File.Exists(filename))
        {
            // Set the files attributes to normal in case it's read-only.

            File.SetAttributes(filename, FileAttributes.Normal);

            // Calculate the total number of sectors in the file.
            double sectors = Math.Ceiling(new FileInfo(filename).Length/512.0);

            // Create a dummy-buffer the size of a sector.

            byte[] dummyBuffer = new byte[512];

            // Create a cryptographic Random Number Generator.
            // This is what I use to create the garbage data.

            RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

            // Open a FileStream to the file.
            FileStream inputStream = new FileStream(filename, FileMode.Open);
            for (int currentPass = 0; currentPass < timesToWrite; currentPass++)
            {
                UpdatePassInfo(currentPass + 1, timesToWrite);

                // Go to the beginning of the stream

                inputStream.Position = 0;

                // Loop all sectors
                for (int sectorsWritten = 0; sectorsWritten < sectors; sectorsWritten++)
                {
                    UpdateSectorInfo(sectorsWritten + 1, (int) sectors);

                    // Fill the dummy-buffer with random data

                    rng.GetBytes(dummyBuffer);

                    // Write it to the stream
                    inputStream.Write(dummyBuffer, 0, dummyBuffer.Length);
                }
            }

            // Truncate the file to 0 bytes.
            // This will hide the original file-length if you try to recover the file.

            inputStream.SetLength(0);

            // Close the stream.
            inputStream.Close();

            // As an extra precaution I change the dates of the file so the
            // original dates are hidden if you try to recover the file.

            DateTime dt = new DateTime(2037, 1, 1, 0, 0, 0);
            File.SetCreationTime(filename, dt);
            File.SetLastAccessTime(filename, dt);
            File.SetLastWriteTime(filename, dt);

            // Finally, delete the file

            File.Delete(filename);

            WipeDone();
        }
    }
    catch(Exception e)
    {
        WipeError(e);
    }
}

I have added some events just to be able to keep track of what's happening during the process.

  • PassInfoEvent - Returns which pass is running and the total number of passes to be run.
  • SectorInfoEvent - Returns which sector is being written to and the total number of sectors to be written to.
  • WipeDoneEvent - An indicator that the wipe process is done.
  • WipeErrorEvent - Returns the exception if anything went wrong.

Acknowledgements

I'd like to thank PIEBALDconsult for his time and help in the forum while working with this.

History

  • 7 January, 2008 -- Original version posted
  • 14 January, 2008 -- First update

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Johan Martensson

Web Developer

Sweden Sweden

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionWhy do you assume 512-byte sectors? Pinmemberyjj5:14 28 Jan '08  
AnswerRe: Why do you assume 512-byte sectors? PinmemberJohan Martensson5:58 28 Jan '08  
GeneralRe: Why do you assume 512-byte sectors? Pinmemberyjj20:41 28 Jan '08  
GeneralNotice about System Resotre PinmemberPrzemyslaw Celej12:55 14 Jan '08  
GeneralSome doubts [modified] PinmvpLuc Pattyn14:55 7 Jan '08  
GeneralRe: Some doubts PinmemberPIEBALDconsult16:03 7 Jan '08  
GeneralRe: Some doubts PinmvpLuc Pattyn16:28 7 Jan '08  
GeneralRe: Some doubts PinmemberJohan Martensson21:04 7 Jan '08  
<small>1.
if you write to a file stream, rewind, write again, rewind, etc, what assures you
that each of these passes gets actually written to disk? it could as well be memory bytes
that get written all the time, and only when the stream gets closed it is committed
to the file system's cache and after that also to the disk. So it might well be that only
the final pass's data makes it to the disk, if so what is the sense of the many passes?</small>
It's true and not, I ran a test like this, first pass 0, second pass 1, third pass 3 and so on, having a break-point after each pass.
When checking the disc in hex-view using Disk Investigator after each pass, all but the last sector is written to.
The conclusion I came to is that it doesn't release the dummybuffer to disc until I call Filestream.Write a second time or Filestream.Close, but it does write to the disc in each pass.
<small>2.
if you write to an existing file, what guarantee do you have that the same physical sectors
will be reused? The data gets cached, then flushed to disk; the file system will discover
it can write entire sectors or clusters, but could choose to change the actual sectors/
clusters being used (e.g. in an attempt to reduce disk fragmentation on the go).
I guess it will not, most of the time, but is there any documented guarantee? And does
it apply to all kinds of file systems? (local FAT, FAT32, NTFS,...) and remote file
systems (Windows or other).</small>
When I use Disc Investigator, I can step each cluster and sector on the disc so I can see it's the right parts on the disc that gets overwritten on FAT, FAT32 and NTFS.
However, this is tested on a clean disc so the fragmentation could be a problem in some cases.
 
http://johanmartensson.se - Home of MPEG4Watcher

GeneralRe: Some doubts PinmvpLuc Pattyn2:18 8 Jan '08  
GeneralRe: Some doubts PinmemberJohan Martensson4:22 8 Jan '08  
GeneralWhoops PinmemberPIEBALDconsult5:13 7 Jan '08  
GeneralRe: Whoops PinmemberJohan Martensson6:57 7 Jan '08  
GeneralVery Nice Pinmembermerlin9814:36 7 Jan '08  
GeneralRe: Very Nice PinmemberJohan Martensson5:17 7 Jan '08  
QuestionFilling the file with 0 would work? PinmemberJcmorin3:44 7 Jan '08  
AnswerRe: Filling the file with 0 would work? PinmemberJohan Martensson4:03 7 Jan '08  
QuestionRe: Filling the file with 0 would work? PinmemberVladimir N.19:21 8 Jan '08  
GeneralRe: Filling the file with 0 would work? PinmemberJohan Martensson21:38 8 Jan '08  
AnswerRe: Filling the file with 0 would work? PinmemberVladimir N.22:33 8 Jan '08  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web02 | 2.5.120529.1 | Last Updated 14 Jan 2008
Article Copyright 2008 by Johan Martensson
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid