【发布时间】:2015-01-16 09:43:59
【问题描述】:
我正在编写一个用于安全擦除文件的小实用程序。目前,我提出了两种擦除方案:random(用垃圾数据填充文件然后擦除)和zeroes(用零填充文件然后擦除)。稍后我会添加更多方案。
有方法的源码(灵感来自this project):
public void WipeFile(string filename, int timesToWrite, WipeScheme scheme)
{
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 / (double)SectorSize);
// Create a dummy-buffer the size of a sector.
byte[] dummyBuffer = new byte[SectorSize];
if (scheme == WipeScheme.Zeroes)
{
Array.Clear(dummyBuffer, 0, dummyBuffer.Length);
}
// 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.
using (FileStream inputStream = new FileStream(filename, FileMode.Open))
{
for (int currentPass = 0; currentPass < timesToWrite; currentPass++)
{
// Go to the beginning of the stream
inputStream.Position = 0;
// Loop all sectors
for (long sectorsWritten = 0; sectorsWritten < sectors; sectorsWritten++)
{
if (scheme == WipeScheme.Random)
{
// 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);
// Flush the stream.
inputStream.Flush();
}
// 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(1901, 1, 1, 0, 0, 0);
File.SetCreationTime(filename, dt);
File.SetLastAccessTime(filename, dt);
File.SetLastWriteTime(filename, dt);
// Finally, delete the file
File.Delete(filename);
}
}
catch (Exception e)
{
// TODO
}
}
该程序似乎运行良好,但我在进行基准测试时发现了奇怪的结果(我在外部硬盘上进行了多次测试,文件大小为 592 MB):
- 用随机数据擦除:大约 7 秒擦除,等于 85 MB/s 的写入速度,看起来还可以。
- 用零数据擦除:大约 500 毫秒擦除,等于 1.2 GB/s 的写入速度!什么?不可能!
最后的结果很好奇,所以我决定禁用从磁盘中删除来测试至少写入是否正确。为此,我评论inputStream.SetLength(0); 和File.Delete(filename);。
现在,结果如下:
- 用随机数据擦除:大约 9 秒擦除,等于 67 MB/s 的写入速度。嗯,有点慢,但没关系,因为它毕竟使用了
RNGCryptoServiceProvider(这很慢)。 - 擦除零数据:大约需要 7 秒擦除,等于 85 MB/s 的写入速度。 比以前更好,更逼真!
我认为是这样的:写入首先在内存中的缓冲区中完成。然后,将缓冲区写入(刷新)到磁盘上。这解释了为什么只写零比写垃圾数据快:获取随机值非常慢。如此之多,以至于缓冲区有时间刷新到磁盘。
但是当我立即删除文件时,文件只是从磁盘中删除并且缓冲区(或其中的一部分)没有被刷新!为什么?这没有用,因为文件被删除,或者缓冲区没有时间刷新。我不知道。
那么,我该怎么办?在这里禁用所有缓存是否可能且足够?还是应该在每次迭代中调用Flush()?
哦,我把安全放在首位!
【问题讨论】:
-
可能
inputStream.SetLength(0);会阻止一切都是 Flush()' ed -
好点!我会测试...
-
@DrKoch 好的,你说得对。我只用评论的这条线再次进行基准测试,结果是商品!我想我不能做更多的事情来让它更快或更安全。
标签: c# .net security file-io buffer