Skip to content

Commit

Permalink
Add switch to include file and directory names in the hash computatio…
Browse files Browse the repository at this point in the history
…n. Add support for MD5. Better argument parsing code.
  • Loading branch information
idrassi committed Jul 15, 2015
1 parent 91a376e commit 4137637
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 126 deletions.
219 changes: 97 additions & 122 deletions DirHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* for sorting. Based on OpenSSL for hash algorithms in order to support all versions
* of Windows from 2000 to 7 without relying on the presence of any specific CSP.
*
* Copyright (c) 2010 Mounir IDRASSI <[email protected]>. All rights reserved.
* Copyright (c) 2010-2015 Mounir IDRASSI <[email protected]>. All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Expand Down Expand Up @@ -33,6 +33,7 @@
#include <tchar.h>
#include <strsafe.h>
#include <openssl/sha.h>
#include <openssl/md5.h>
#include <list>
using namespace std;

Expand All @@ -58,6 +59,23 @@ class Hash
static Hash* GetHash(LPCTSTR szHashId);
};

class Md5 : public Hash
{
protected:
MD5_CTX m_ctx;
public:
Md5() : Hash()
{
MD5_Init(&m_ctx);
}

void Init() { MD5_Init(&m_ctx);}
void Update(LPBYTE pbData, DWORD dwLength) { MD5_Update(&m_ctx, pbData, dwLength);}
void Final(LPBYTE pbDigest) { MD5_Final(pbDigest, &m_ctx);}
LPCTSTR GetID() { return _T("MD5");}
int GetHashSize() { return 16;}
};

class Sha1 : public Hash
{
protected:
Expand Down Expand Up @@ -144,7 +162,10 @@ Hash* Hash::GetHash(LPCTSTR szHashId)
{
return new Sha512();
}

if (_tcsicmp(szHashId, _T("MD5")) == 0)
{
return new Md5();
}
return NULL;
}

Expand All @@ -158,7 +179,10 @@ class CDirContent
public:
CDirContent(LPCWSTR szPath, LPCWSTR szName, bool bIsDir) : m_bIsDir(bIsDir), m_szPath(szPath)
{
if (szPath[wcslen(szPath) - 1] != _T('\\') && szPath[wcslen(szPath) - 1] != _T('/'))
if (szPath[wcslen(szPath) - 1] == _T('/'))
m_szPath[wcslen(szPath) - 1] = _T('\\');

if (szPath[wcslen(szPath) - 1] != _T('\\'))
m_szPath += _T("\\");
m_szPath += szName;
}
Expand All @@ -170,15 +194,26 @@ class CDirContent
operator LPCWSTR () { return m_szPath.c_str();}
};

DWORD HashFile(LPCTSTR szFilePath, Hash* pHash)
DWORD HashFile(LPCTSTR szFilePath, Hash* pHash, bool bIncludeNames)
{
DWORD dwError = 0;
FILE* f = _tfopen(szFilePath, _T("rb"));
FILE* f = NULL;

if (bIncludeNames)
{
TCHAR szCanonalizedName[MAX_PATH + 1];
if (!PathCanonicalize (szCanonalizedName, szFilePath))
lstrcpy (szCanonalizedName, szFilePath);
pHash->Update ((LPBYTE) szCanonalizedName, _tcslen (szCanonalizedName) * sizeof(TCHAR));
}

f = _tfopen(szFilePath, _T("rb"));
if(f)
{
size_t len;
while ( (len = fread(g_pbBuffer, 1, sizeof(g_pbBuffer), f)) != 0)
pHash->Update(g_pbBuffer, len);

fclose(f);
}
else
Expand All @@ -189,14 +224,22 @@ DWORD HashFile(LPCTSTR szFilePath, Hash* pHash)
return dwError;
}

DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash)
DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash, bool bIncludeNames)
{
wstring szDir;
WIN32_FIND_DATA ffd;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;
list<CDirContent> dirContent;

if (bIncludeNames)
{
TCHAR szCanonalizedName[MAX_PATH + 1];
if (!PathCanonicalize (szCanonalizedName, szDirPath))
lstrcpy (szCanonalizedName, szDirPath);
pHash->Update ((LPBYTE) szCanonalizedName, _tcslen (szCanonalizedName) * sizeof(TCHAR));
}

szDir += szDirPath;
szDir += _T("\\*");

Expand Down Expand Up @@ -247,13 +290,13 @@ DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash)
{
if (it->IsDir())
{
dwError = HashDirectory( it->GetPath(), pHash);
dwError = HashDirectory( it->GetPath(), pHash, bIncludeNames);
if (dwError)
break;
}
else
{
dwError = HashFile(it->GetPath(), pHash);
dwError = HashFile(it->GetPath(), pHash, bIncludeNames);
if (dwError)
break;
}
Expand All @@ -264,7 +307,7 @@ DWORD HashDirectory(LPCTSTR szDirPath, Hash* pHash)

void ShowUsage()
{
_tprintf(TEXT("Usage: DirHash.exe DirectoryOrFilePath [HashAlgo] [-t ResultFileName] [-nowait]\n Possible values for HashAlgo (not case sensitive) : \n - SHA1\n - SHA256\n - SHA384\n - SHA512\n ResultFileName specifies a text file where the result will be appended\n"));
_tprintf(TEXT("Usage: DirHash.exe DirectoryOrFilePath [HashAlgo] [-t ResultFileName] [-nowait] [-hashnames]\n Possible values for HashAlgo (not case sensitive, default is SHA1) : \n - MD5\n - SHA1\n - SHA256\n - SHA384\n - SHA512\n\n ResultFileName specifies a text file where the result will be appended\n\n -nowait avoids displaying the waiting prompt before exiting\n\n -hashnames indicates that file names will be included in the hash computation"));
}

void WaitForExit(bool bDontWait = false)
Expand All @@ -286,136 +329,68 @@ int _tmain(int argc, _TCHAR* argv[])
Hash* pHash = NULL;
FILE* outputFile = NULL;
bool bDontWait = false;
bool bIncludeNames = false;

setbuf (stdout, NULL);

SetConsoleTitle(_T("DirHash by Mounir IDRASSI ([email protected]) Copyright 2010-2015"));

_tprintf(_T("\nDirHash by Mounir IDRASSI ([email protected]) Copyright 2010\nRecursively compute hash of a given directory content in lexicographical order.\nIt can also compute the hash of a single file.\n\nSupported Algorithms : SHA1, SHA256, SHA384, SHA512\nUsing OpenSSL\n\n"));
_tprintf(_T("\nDirHash by Mounir IDRASSI ([email protected]) Copyright 2010-2015\nRecursively compute hash of a given directory content in lexicographical order.\nIt can also compute the hash of a single file.\n\nSupported Algorithms : MD5, SHA1, SHA256, SHA384, SHA512\nUsing OpenSSL\n\n"));

if (argc < 2 || argc > 6)
if (argc < 2 || argc > 7)
{
ShowUsage();
WaitForExit();
return 1;
}

if (argc == 3)
if (argc >= 3)
{
if (_tcsicmp(argv[2], _T("-nowait")) == 0)
for (int i = 2; i < argc; i++)
{
bDontWait = true;
pHash = new Sha1();
}
else
{
pHash = Hash::GetHash(argv[2]);
if (!pHash)
if (_tcscmp(argv[i],_T("-t")) == 0)
{
ShowUsage();
WaitForExit();
return 1;
if ((i + 1) >= argc)
{
// missing file argument
ShowUsage();
WaitForExit();
return 1;
}

outputFile = _tfopen(argv[i + 1], _T("a+t"));
if (!outputFile)
{
_tprintf(_T("Failed to open the result file for writing!\n"));
WaitForExit();
return 1;
}

i++;
}
}
}
else if (argc == 4)
{
if (_tcscmp(argv[2],_T("-t")) == 0)
{
outputFile = _tfopen(argv[3], _T("a+t"));
if (!outputFile)
{
_tprintf(_T("Failed to open the result file for writing!\n"));
WaitForExit();
return 1;
}
pHash = new Sha1();
}
else if (_tcscmp(argv[3],_T("-nowait")) == 0)
{
bDontWait = true;
pHash = Hash::GetHash(argv[2]);
if (!pHash)
else if (_tcscmp(argv[i],_T("-nowait")) == 0)
{
ShowUsage();
WaitForExit();
return 1;
}
}
else
{
ShowUsage();
WaitForExit();
return 1;
}

}
else if (argc == 5)
{
if (_tcscmp(argv[2],_T("-t")) && _tcscmp(argv[3],_T("-t")))
{
ShowUsage();
WaitForExit();
return 1;
}
if (_tcscmp(argv[2],_T("-t")) == 0)
{
if (_tcscmp(argv[4], _T("-nowait")))
bDontWait = true;
}
else if (_tcscmp(argv[i],_T("-hashnames")) == 0)
{
ShowUsage();
WaitForExit();
return 1;
bIncludeNames = true;
}
else
{
pHash = Hash::GetHash(argv[i]);
if (!pHash)
{
if (outputFile) fclose(outputFile);
ShowUsage();
WaitForExit();
return 1;
}
}
bDontWait = true;
outputFile = _tfopen(argv[3], _T("a+t"));
pHash = new Sha1();
}
else
{
outputFile = _tfopen(argv[4], _T("a+t"));
pHash = Hash::GetHash(argv[2]);
}
if (!outputFile)
{
_tprintf(_T("Failed to open the result file for writing!\n"));
if (pHash) delete pHash;
WaitForExit();
return 1;
}
if (!pHash)
{
if (outputFile) fclose(outputFile);
ShowUsage();
WaitForExit();
return 1;
}
}
else if (argc == 6)
{
if (_tcscmp(argv[3],_T("-t")) || _tcscmp(argv[5],_T("-nowait")))
{
ShowUsage();
WaitForExit();
return 1;
}

outputFile = _tfopen(argv[4], _T("a+t"));
pHash = Hash::GetHash(argv[2]);
if (!outputFile)
{
_tprintf(_T("Failed to open the result file for writing!\n"));
if (pHash) delete pHash;
WaitForExit();
return 1;
}
if (!pHash)
{
if (outputFile) fclose(outputFile);
ShowUsage();
WaitForExit();
return 1;
}
bDontWait = true;
}
else
if (!pHash)
pHash = new Sha1();

// Check that the input path plus 3 is not longer than MAX_PATH.
Expand All @@ -435,7 +410,7 @@ int _tmain(int argc, _TCHAR* argv[])
{
if (outputFile) fclose(outputFile);
delete pHash;
_tprintf(TEXT("Error: The given path doesn't exist\n"), MAX_PATH);
_tprintf(TEXT("Error: The given input file doesn't exist\n"));
WaitForExit(bDontWait);
return (-2);
}
Expand All @@ -446,9 +421,9 @@ int _tmain(int argc, _TCHAR* argv[])
fflush(stdout);

if (PathIsDirectory(argv[1]))
dwError = HashDirectory(argv[1], pHash);
dwError = HashDirectory(argv[1], pHash, bIncludeNames);
else
dwError = HashFile(argv[1], pHash);
dwError = HashFile(argv[1], pHash, bIncludeNames);

if (dwError == NO_ERROR)
{
Expand Down
8 changes: 4 additions & 4 deletions DirHash.rc
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,2,0,0
PRODUCTVERSION 1,2,0,0
FILEVERSION 1,3,0,0
PRODUCTVERSION 1,3,0,0
FILEFLAGSMASK 0x17L
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -72,12 +72,12 @@ BEGIN
VALUE "Comments", "By Mounir IDRASSI"
VALUE "CompanyName", "IDRIX"
VALUE "FileDescription", "compute Hash of dorectories and files"
VALUE "FileVersion", "1, 2, 0, 0"
VALUE "FileVersion", "1, 3, 0, 0"
VALUE "InternalName", "DirHash"
VALUE "LegalCopyright", "Copyright (C) 2015 IDRIX"
VALUE "OriginalFilename", "DirHash.exe"
VALUE "ProductName", "DirHash Application"
VALUE "ProductVersion", "1, 2, 0, 0"
VALUE "ProductVersion", "1, 3, 0, 0"
END
END
BLOCK "VarFileInfo"
Expand Down

0 comments on commit 4137637

Please sign in to comment.