3
\$\begingroup\$

I'm pretty new and I posted on SO earlier because I wanted to make sure my code was right and all that and I got redirected here. So I have this code that I put together (using Example C Program: Creating an MD5 Hash from File Content and some some other code I found online) to try to hash a directory in SHA256. I am still somewhat a noob in programming so I'd love to get any kind of feedback on the code. I basically just mixed the directory iterator and hashing function together. Also, I get a different hash when I run this function on a directory than another program I have. Someone pointed out that it might be because I read the files in a different order. He also pointed out that my code was "brittle". Is there any way I can improve this. How do I ensure that I get a "correct" hash?

Here's the code:

#include <stdio.h>
#include <windows.h>
#include <Wincrypt.h>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <experimental/filesystem>
#define BUFSIZE 1024
#define SHA256LEN 32
#define PATH "C:\\SomeUser\\SomeDirectory"

using namespace std;
namespace filesys = std::experimental::filesystem;


std::vector<std::string> getAllFilesInDir(const std::string& dirPath, const std::vector<std::string> dirSkipList = { })
{
    // Create a vector of string
    std::vector<std::string> listOfFiles;
    try {
        // Check if given path exists and points to a directory
        if (filesys::exists(dirPath) && filesys::is_directory(dirPath))
        {
            // Create a Recursive Directory Iterator object and points to the starting of directory
            filesys::recursive_directory_iterator iter(dirPath);
            // Create a Recursive Directory Iterator object pointing to end.
            filesys::recursive_directory_iterator end;
            // Iterate till end
            while (iter != end)
            {
                // Check if current entry is a directory and if exists in skip list
                if (filesys::is_directory(iter->path()) &&
                    (std::find(dirSkipList.begin(), dirSkipList.end(), iter->path().filename()) != dirSkipList.end()))
                {
                    // Skip the iteration of current directory pointed by iterator
#ifdef USING_BOOST
// Boost Fileystsem  API to skip current directory iteration
                    iter.no_push();
#else
// c++17 Filesystem API to skip current directory iteration
                    iter.disable_recursion_pending();
#endif
                }
                else
                {
                    // Add the name in vector
                    listOfFiles.push_back(iter->path().string());
                }
                error_code ec;
                // Increment the iterator to point to next entry in recursive iteration
                iter.increment(ec);
                if (ec) {
                    std::cerr << "Error While Accessing : " << iter->path().string() << " :: " << ec.message() << '\n';
                }
            }
        }
    }
    catch (std::system_error& e)
    {
        std::cerr << "Exception :: " << e.what();
    }
    return listOfFiles;
}



DWORD hashDirectory()
{
    DWORD dwStatus = 0;

    BOOL bResult = FALSE;
    HCRYPTPROV hProv = 0;
    HCRYPTHASH hHash = 0;
    HANDLE hFile = NULL;
    BYTE rgbFile[BUFSIZE];
    DWORD cbRead = 0;
    BYTE rgbHash[SHA256LEN];
    DWORD cbHash = 0;
    CHAR rgbDigits[] = "0123456789abcdef";

    std::vector<std::string> listOfFiles = getAllFilesInDir(PATH);

    for (auto str : listOfFiles)
    {
        if (!filesys::is_directory(str))
        {
            LPCSTR filename = str.c_str();


            // Logic to check usage goes here.

            hFile = CreateFile(filename,
                GENERIC_READ,
                FILE_SHARE_READ,
                NULL,
                OPEN_EXISTING,
                FILE_FLAG_SEQUENTIAL_SCAN,
                NULL);

            if (INVALID_HANDLE_VALUE == hFile)
            {
                dwStatus = GetLastError();
                printf("Error opening file %s\nError: %d\n", filename,
                    dwStatus);
                return dwStatus;
            }

            // Get handle to the crypto provider
            if (!CryptAcquireContext(&hProv,
                NULL,
                NULL,
                PROV_RSA_AES,
                CRYPT_VERIFYCONTEXT)
            )
            {
                dwStatus = GetLastError();
                printf("CryptAcquireContext failed: %d\n", dwStatus);
                CloseHandle(hFile);
                return dwStatus;
            }


            if (!CryptCreateHash(hProv, CALG_SHA_256, 0, 0, &hHash))
            {
                dwStatus = GetLastError();
                printf("CryptAcquireContext failed: %d\n", dwStatus);
                CloseHandle(hFile);
                CryptReleaseContext(hProv, 0);
                return dwStatus;
            }

            while (bResult = ReadFile(hFile, rgbFile, BUFSIZE,
                &cbRead, NULL))
            {
                if (0 == cbRead)
                {
                    break;
                }

                if (!CryptHashData(hHash, rgbFile, cbRead, 0))
                {
                    dwStatus = GetLastError();
                    printf("CryptHashData failed: %d\n", dwStatus);
                    CryptReleaseContext(hProv, 0);
                    CryptDestroyHash(hHash);
                    CloseHandle(hFile);
                    return dwStatus;
                }
            }

            if (!bResult)
            {
                dwStatus = GetLastError();
                printf("ReadFile failed: %d\n", dwStatus);
                CryptReleaseContext(hProv, 0);
                CryptDestroyHash(hHash);
                CloseHandle(hFile);
                return dwStatus;
            }
        }
    }

            cbHash = SHA256LEN;


            if (CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0))
            {
                //printf("SHA256 hash of file %s is: ", filename);
                printf("sha256 Files:");
                for (DWORD i = 0; i < cbHash; i++)
                {
                    printf("%c%c", rgbDigits[rgbHash[i] >> 4],
                        rgbDigits[rgbHash[i] & 0xf]);
                }
                printf("\n");


            }
            else
            {
                dwStatus = GetLastError();
                printf("CryptGetHashParam failed: %d\n", dwStatus);
            }

            CryptDestroyHash(hHash);
            CryptReleaseContext(hProv, 0);
            CloseHandle(hFile);

    return dwStatus;
}
\$\endgroup\$
2
  • \$\begingroup\$ Is there something wrong with the indentation at the end of the code? \$\endgroup\$ – L. F. Jul 14 '19 at 5:18
  • \$\begingroup\$ Oh yeah I think it's supposed to be all the way to left because the for loop ends right above \$\endgroup\$ – Newbie123 Jul 15 '19 at 6:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.