#1
|
|||
|
|||
Segmented File Hashing Utility
This is a small command line utility for MS-Windows written in C in VisualStudio 2019, which creates multiple MD5 hashes of a single file. Also known as "segmented hashing".
USAGE: SegmentedHash.exe FileToHash NumberOfHashSegments OffsetRange e.g.: 1BEEF-20000 For example: SegmentedHash.exe BigFile.bin 100 ...calculates 100 consecutive MD5 hashes of the entire Bigfile.bin file. In other words: it divides the BigFile.bin into 100 equal size segments and calculates an MD5 hash of each segment. SegmentedHash.exe BigFile.bin 100 642c06f40-642f509a6 ...calculates 100 consecutive MD5 hashes of the partial Bigfile.bin starting from the hexadecimal offset 642c06f40 and ending at the offset 642f509a6 (inclusive). The file offsets can also be specified in an open form, e.g.: -1CB2 means from the beginning of the file (offset 0) up to the file offset 0x1cb2 and 1BC2- means from the file offset 0x1cb2 up to the end of file. The hashing algorithm can be changed by altering the line: #define ALGORITHM Other possible algorithms are: CALG_SHA1, CALG_SHA_256, CALG_SHA_512, CALG_3DES, CALG_AES_128, etc... Note: This utility does not write any files. It only reads the file in BUFSIZE chunks (see the source in SegmentedHash.cpp) and calculates the hashes. Q: WHAT IS THIS USEFUL FOR? A: Scenario: You have been downloading a 16TB file over a slow FTP connection for a week but several bytes of the file came over corrupted. This utility allows you to detect which bytes did not transfer correctly without doing the full 16TB file compare / re-download. This is done by running the SegmentedHash utility on the FTP server AND on the FTP client machine and comparing only the hashes of that big file before and after the transfer. Once a mismatching hash is identified, you can narrow down the search to a smaller range of file offsets and find the corrupted bytes. Just several kB of hashes need to be transferred and compared to find the culprit in a huge file. Once this is done the correct bytes can be downloaded anew and used to patch the huge downloaded corrupted file. Code:
#include < stdio.h > #include < assert.h > #include < windows.h > #include < Wincrypt.h > #define ALGORITHM CALG_MD5 #define BUFSIZE 4096 DWORD PrintHash(HCRYPTHASH hHash) { DWORD cbData = sizeof(DWORD); PBYTE pbData = NULL; DWORD cHashSize; CHAR Digits[] = "0123456789abcdef"; DWORD dwStatus = 0; if (!CryptGetHashParam(hHash, HP_HASHSIZE, (PBYTE)&cHashSize, &cbData, 0) && (cbData != sizeof(cHashSize))) goto ErrorExit; pbData = (PBYTE)malloc(cHashSize); if ((pbData) && (CryptGetHashParam(hHash, HP_HASHVAL, pbData, &cHashSize, 0))) { for (DWORD i = 0; i < cHashSize; i++) { printf("%c%c", Digits[pbData[i] >> 4], Digits[pbData[i] & 0xf]); } printf("\n"); goto Exit; } ErrorExit: dwStatus = GetLastError(); printf("ERROR: CryptGetHashParam failed: %08x\n", dwStatus); Exit: if (pbData) free(pbData); return dwStatus; } LONGLONG mySetFilePointer(HANDLE hFile, LONGLONG distance, DWORD MoveMethod) { LARGE_INTEGER dist; dist.QuadPart = distance; dist.LowPart = SetFilePointer(hFile, dist.LowPart, &dist.HighPart, MoveMethod); if (dist.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) { dist.QuadPart = -1; } return dist.QuadPart; } int wmain(int argc, wchar_t* argv[]) { LARGE_INTEGER fsize; ULONGLONG NextToRead = 0; ULONGLONG SegFirst=0; ULONGLONG SegLast = 0; ULONGLONG SegSize; ULONGLONG WindowFirst = 0; ULONGLONG WindowLast = 0; ULONGLONG WindowSize; ULONGLONG nSegments = 1; ULONGLONG Remainder = 0; DWORD dwStatus = 0; BOOL bResult = FALSE; HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; HANDLE hFile = NULL; BYTE Bufffer[BUFSIZE]; DWORD cbRead = 0; wchar_t* EndPtr; ULONGLONG tmp; LPCWSTR filename = argv[1]; // Logic to check usage goes here. if (argc < 2) { printf("USAGE: FileToHash NumberOfHashSegments Last edited by HarrySpoofer; 08-19-2023 at 17:16. |
The Following 5 Users Say Thank You to HarrySpoofer For This Useful Post: | ||
MarcElBichon (08-19-2023), ontryit (08-24-2023), pnta (10-14-2023), tonyweb (08-21-2023), Zeokat (08-20-2023) |
#2
|
|||
|
|||
Nice piece of code!
is it possible to make it cross-platform and be available for Linux flavors as well? |
#3
|
|||
|
|||
Similar to how the torrent protocol works. Unfortunately ftp and http don't have this functionality built into the protocol so without something like ssh access this isn't going to do much such as downloading from public servers.
Practically I don't think a segment of over 2 megabytes without a hash is a good idea. Companies like Microsoft give md5 or sha1 hashes of multigigabyte ISOs for example. But giving a 2MB segmented sets of hashes is still a very small amount of data. Not sure why at this day and age, this is not solved. Bandwidth efficiency for large downloads remains an annoying issue in various contexts. |
#4
|
|||
|
|||
Quote:
This means that the FTP server owner also must know about this tool and then run this tool on their server side. Or it is useful only in cases when you are transferring files between your own servers... |
The Following User Says Thank You to Moe For This Useful Post: | ||
Rebe (09-17-2023) |
#5
|
|||
|
|||
That's a good point. Is there a compiled version handy?
|
#6
|
|||
|
|||
Hello, nice tool, another good option for something like this is using PAR2 / PAR3 which support error recovering too
https://en.wikipedia.org/wiki/Parchive |
Tags |
file, hashing, utility |
Thread Tools | |
Display Modes | |
|
|