2

I need to create a checksum for an entire USB Drive. I want to be able to get a checksum for the entire USB Drive when I put files on it and then be able to get another checksum later to check that nothing has changed (viruses, updates to files, etc).

Right now, I'm finding checksums for all of the individual files, placing them into a StringBuilder, and then getting a checksum for that StringBuilder once all of the checksums have been placed.

private string ChecksumFolder(string path)
{
    string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);

    StringBuilder allChecksum = new StringBuilder();

    for (int count = 0; count < files.Length; count++)
    {
        allChecksum.Append(CreateChecksumFromFile(files[count]));
    }

    return CreateChecksumFromString(allChecksum.ToString());
}

I'm running into issues with the "System Volume Information" folder, which is causing an exception at the Directory.GetFiles() line. The checksum for the files and the StringBuilder works just fine when used on other folders.

Do you know of either another way to create a checksum for an entire USB or a way to programmatically get into that System Volume Information folder?

Thanks in advance!

EDIT: Adding CreateChecksumFromFile (the String version is essentially the same, just using a different kind of stream for the checksum)

private string CreateChecksumFromFile(string file)
{
    string mChecksum;
    using (FileStream stream = File.OpenRead(file))
    {
        SHA1CryptoServiceProvider sha = new SHA1CryptoServiceProvider();
        byte[] checksum = sha.ComputeHash(stream);
        mChecksum = BitConverter.ToString(checksum).Replace("-", String.Empty);
        sha.Clear();
    }
    return mChecksum;
}
Sach
  • 10,091
  • 8
  • 47
  • 84
  • What's the exception? And what does the `CreateChecksumFromString()` and `CreateChecksumFromFile()` methods look like? Also, a related tip, use `EnumerateFiles()` instead of `GetFiles()` as it's faster. – Sach Sep 06 '18 at 16:48
  • It's a UnauthorizedAccessException with the message "Access to the path 'E:\System Volume Information' is denied." Also, the program requests Administrative privileges – sailorstar165 Sep 06 '18 at 16:51
  • You can google what that peculiar "System Volume Information" folder is. I don't know what the purpose of the hash/checksum value is, but i lean towards the suggestion to exclude such system-specific folders from your checksum calculation. –  Sep 06 '18 at 16:51
  • OK so it's pretty self explanatory - you're trying to access files that you don't have authority to access. – Sach Sep 06 '18 at 16:52
  • I'm guessing the exception is thrown at this line? `using (FileStream stream = File.OpenRead(file))` I would avoid those files without access and calculate checksum for the rest. – Sach Sep 06 '18 at 17:05
  • @Sach: The exception occurs at `Directory.GetFiles()` – sailorstar165 Sep 06 '18 at 17:07
  • Check out this answer. https://stackoverflow.com/a/10767422/302248 You can use it to access only the accessible files. – Sach Sep 06 '18 at 17:11
  • @Sach: The problem is, I want to do a checksum of everything. The idea is that because we can't make the entire USB drive read only (not really, anyway), we want to be able to have a checksum we can point to when someone comes back saying we gave them a USB with a virus to show that something changed on the USB drive after we gave it to them (i.e. we didn't give them a USB with a virus, that happened after they got it) – sailorstar165 Sep 06 '18 at 17:16
  • If your actual intention/problem is to make USB drive(s) read-only, look here for example: https://superuser.com/questions/769299/how-will-i-make-a-pendrive-write-protected (or here: https://www.getusb.info/how-to-make-a-usb-read-only/). No need for the checksumming-bonanza (a client who suspects that you gave them a virus will probably not trust you much even when presented with "original" checksums they cannot verify anyway...) –  Sep 06 '18 at 17:39
  • @elgonzo: That sets it as read-only in the registry. The way I understand it, the USB is read-and-write enabled until the registry edit completes, meaning it's open up to viruses for however long. And if the computer it's plugged into blocks auto-runs, well, I'm out of luck. Thanks for the suggestion though! – sailorstar165 Sep 06 '18 at 17:45
  • Another suggestion, as your problem seems to be to demonstrate to your clients that the USB sticks you give them are malware-free, why don't you virus-scan your USB sticks before handing them over, and provide the result/log of that scan to the client if requested (or by default)? –  Sep 06 '18 at 17:46
  • Do you want to checksum the whole USB drive, or just the areas used by files? Things can lurk in "unused" space. – Ben Voigt Sep 06 '18 at 18:45
  • @BenVoigt: The idea is to checksum everything on the USB drive. The tactic I was taking was if I check all of the files, things that aren't supposed to be there (like viruses) would get caught up in the checksum. If you know a way to checksum the whole USB (including unused space), that would be extremely helpful. – sailorstar165 Sep 07 '18 at 13:25
  • @sailorstar165: The Win32 function `CreateFile` can be used to open special files as well as ordinary files. For your purposes, it would be desirable to read the raw volume. – Ben Voigt Sep 07 '18 at 14:36
  • @BenVoigt: I'm afraid I don't follow. Could you elaborate a bit more on how to use this? Thanks! – sailorstar165 Sep 07 '18 at 15:02
  • @sailorstar165: Related question here: https://stackoverflow.com/q/38190/103167 Definitely do follow the suggestion of reading the CreateFile documentation, specifically the Remarks section, Volumes and Physical Drives subsection – Ben Voigt Sep 07 '18 at 17:18

1 Answers1

0

OK so you have a two-part problem.

  1. You want to go through all the files in a directory and create a checksum.
  2. There may be some inaccessible files, but you want a way to include them into the checksum as well.

So I'm proposing sort of a workaround solution. - If a file is accessible, create a checksum for it. - If not, add the file name to a list. - Later, when verifying the integrity, we verify both the checksum and the inaccessible file list.

So, assume that the following method uses the example in this SO answer and creates a list of accessible files. But also, in addition, in case a file is inaccessible, it adds it to a list.

private static void FindFiles(string path, string file_pattern, bool recurse, out List<string> accessible, out List<string> inaccessible)
{
    accessible = new List<string>();
    inaccessible = new List<string>();
    // This creates two lists, one with accessible files and one with inaccessible files.
}

Now let's modify your methods.

private string ChecksumFolder(string path, out List<string> inaccessibleFiles)
{
    inaccessibleFiles = null;

    FindFiles(path, "*", true, out List<string> accessible, out List<string> inaccessible);
    inaccessibleFiles = inaccessible;

    StringBuilder allChecksum = new StringBuilder();

    for (int count = 0; count < accessible.Count; count++)
    {
        allChecksum.Append(CreateChecksumFromFile(accessible[count]));
    }

    return CreateChecksumFromString(allChecksum.ToString());
}

Now you have a checksum for that folder by using all the accessible files, and a list of inaccessible files. You save both, and send them to whatever the application that will be verifying the integrity later. And at that end you match the checksum, and also see if the files in the list of inaccessible files are the same.

Sach
  • 10,091
  • 8
  • 47
  • 84