【问题标题】:Scenario that requires to remove or by-pass the filestream's cache/buffer?需要删除或绕过文件流的缓存/缓冲区的场景?
【发布时间】: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


【解决方案1】:

删除

inputStream.SetLength(0);

来自您的代码。

您可能必须再次打开文件(覆盖后)才能将其大小设置为零。

【讨论】:

    猜你喜欢
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 2018-06-28
    • 2023-03-05
    • 2023-03-16
    相关资源
    最近更新 更多