A File Checksum Shell Menu Extension DLL






4.89/5 (32 votes)
Create a File Checksum Shell Menu Extension using ATL and Crypto++
Introduction
A File Checksum is used to verify the integrity of a file. Checksums can detect both transmission errors and tampering. To detect transmission errors, we would use a CRC (cyclic redundancy check) [1]. To detect tampering, we generally choose a cryptographic Hash due to the desirable property of Collision Resistance [2].
This article presents two Shell Extension DLLs which can be used to create file checksums and verify file checksums. The article is based on Michael Dunn's Guide to Writing Shell Extensions, Part I [4], Tom Archer's Using the Clipboard, Part I: Transferring Simple Text [5], and Crypto++. This article will discuss the following topics:
- Shell Extension DLL Usage
- Compiling and Integrating Crypto++
- Windows Clipboard APIs
- Creating a Shell Context Menu Extension DLL
- Crypto++ ChannelSwitch Class
- Command Line Debugging
- Managing an Unstable Windows Explorer
- Character Set Considerations
- Create and Verify Routines
- Miscellaneous
- Visual Studio 2005 and Platform SDK
Microsoft offers a command line file checksum tool published under Knowledge Base article Q841290, Availability and Description of the File Checksum Integrity Verifier Utility [6]. The Microsoft tool supports MD5 and SHA1.
Shell Extension DLL Usage
Should the reader desire to use the Extension DLLs, he or she should download and install as described below. Once the DLLs are registered, they are available as Context Menus when one right clicks a file (or multiple files) in Windows Explorer.
- Download the DLL
- CtxCreateHashDll.zip
- CtxVerifyHashDll.zip
- Unpack to C:\Windows\System\
- Register the DLL
regsvr32.exe C:\Windows\System\CtxCreateHash.Dll
regsvr32.exe C:\Windows\System\CtxVerifyHash.Dll
Windows Vista and User Account Control
To manually run regsvr32.exe under Vista with User Account Control enabled, navigate to the Command Prompt from the Start menu. Right click the Command Prompt and chose Run As Administrator as shown in Figure 1.
![]() |
Figure 1: Run As Administrator
|
Neglecting to run regsvr32 with elevated privileges will usually result in the error, "DllRegisterServer failed with error code 0x80070005," while success is the familiar succeeded shown below.
![]() |
Figure 2: DllRegisterServer Success
|
Visual C++ Runtime
The latest versions of the compiled DLLs are built and linked with Visual Studio 2008. If required, download the Microsoft Visual C++ 2008 Redistributable Package. A classic example of requiring the package is regsvr32 failing to register the DLLs with the error, "This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem"
Checksum Creation
After selecting a files or files, if the user selects Create Checksum, the following hashes are created and placed on the clipboard:
- MD5
- RIPE MD-128, RIPE MD-160, RIPE MD-256, RIPE MD-320
- SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
- Whirlpool
A Message Box is then displayed with the digest of the hashed file or files. A truncated version is displayed to keep the message box size manageable.
|
Figure 3: Truncated Message Box
|
The full checksums are placed on the Windows Clipboard for pasting. Pasting into Notepad from the clipboard reveals the full text.
|
Figure 4: Clipboard Text
|
Checksum Verification
Verifying a file's checksum is equally trivial. Navigate to the web page or document where the checksum resides, highlight, and copy to the clipboard.
|
Figure 5: Copy Checksums to the
Clipboard
|
Navigate to the files, select, right click, and chose Verify Checksum.
|
Figure 6: Verify Checksums
|
Supported verification algorithms are:
- CRC32
- MD2, MD4, MD5
- RIPE MD-128, RIPE MD-160, RIPE MD-256, RIPE MD-320
- SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
- Whirlpool
A message box will be presented similar to below. The message box will group files in two categories: verified and unverified. A verified file will display the message "Verified Checksum" with a digest of the checksum. An unverified file will under the heading "Unverified Checksum"
|
Figure 7: Verify Checksum Message
Box
|
When verifying, the DLL searches for matching hash values in order from strongest to weakest (SHA-512 to CRC32). The match algorithm terminates on a first match, so only the strongest hash is displayed.
Compiling and Integrating Crypto++
The samples provided
use various Crypto++ Symmetric Ciphers. Crypto++ can be downloaded from Wei Dai's
Crypto++ page. For compilation and integration issues, visit
Integrating Crypto++ into the Microsoft Visual C++ Environment. This article
is based upon basic assumptions presented in the previously mentioned article. For
those who are interested in other C++ Cryptographic libraries, please see Peter
Gutmann's Cryptlib
or Victor Shoup's NTL.
Windows Clipboard APIs
Please see Tom Archer's Using the Clipboard, Part I: Transferring Simple Text for an in depth discussion on the subject. Sample 1 demonstrates enumerating the Clipboard's data formats. Sample 2 demonstrates reading text from the Clipboard. Finally, sample 3 demonstrates writing Unicode text to the Clipboard.
|
Figure 8: Writing Clipboard Text
|
Creating a Shell Context Menu Extension DLL
Creating a shell context menu is based extensively on Michael Dunn's Guide to Writing Shell Extensions, Part I. Please refer to Michael's article for the discussion. Michael's techniques works well for inserting a single menu item, or multiple menu items for Windows 2000.
Composition
Unlike Michael's article, we will have to use a slightly different technique
when we call InsertMenu
on Windows XP, Server 2003, and Vista. This is
due to Composition. Composition is a technique that Windows XP and above use to
group context menu items together. In Figure 9 we see two examples of composition.
Adobe is providing two DLLs which are grouped together, and the checksum DLLs are
being grouped together.
![]() |
Figure 9: Composition
|
For a discussion of Composition, see Raymond Chen's series on The Old New Thing. The two chapters of interest are Chapter 10: Composite Extensions - Groundwork and Chapter 11: Composite Extensions - Composition. Keep in mind that Chen's sample code is presented from the shell's perspective rather than our perspective. Due to the side effects of composition in Windows XP, Server 2003, and Vista, we must insert menu items as follows:
InsertMenu( hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION,
uidFirstCmd+1, _T("Create Checksums") );
// Return that we consumed two IDs rather than 1.
// This is because we skipped ID 0 (uidFirstCmd), and
// added ID 1 (uidFirstCmd+1)
//
// This means we must handle Command 1 in InvokeCommand(),
// rather than Command 0
return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_NULL, 2 );
If we added two menu items, our routine would be as follows:
InsertMenu( hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION,
uidFirstCmd+1, _T("Item 1") );
InsertMenu( hmenu, uMenuIndex, MF_STRING | MF_BYPOSITION,
uidFirstCmd+2, _T("Item 2") );
// Return that we consumed three IDs rather than one or two.
// This is because we skipped ID 0 (uidFirstCmd), and
// added ID 1 (uidFirstCmd+1) and added ID 2 (uidFirstCmd+2)
//
// This means we must handle Command 1 and Command 2
// in InvokeCommand(), rather than Command 0
return MAKE_HRESULT( SEVERITY_SUCCESS, FACILITY_NULL, 3 );
The shell's algorithm which determines what items should be composted (and how they are arranged) is not available. But it appears that it depends on:
- Registry string name of the DLL
- Number of leading characters which match in a string compare
It appears the algorithm resides somewhere in the Shell's Shell32!_imp__DSA_InsertItem
function. The rule of thumb observed is if two or more characters match in the registry
string, the items will be composted.
Crypto++ ChannelSwitch Class
Retrieving from the disk multiple times can become a bottleneck for performance.
This is especially true if we are reading the same file continuously. To overcome
the multiple disk read issue, one can use the Crypto++ ChannelSwitch
class. The ChannelSwitch
class allows a user to stream data to multiple
HashFilter
based objects after a single disk read. More correctly,
one can push data to any BufferedTransformation
derived object. This
is trivial when performing string (in memory) based operations; however disk based
operations tax response times. One would not want to read a 1 MB file 6 times to
send it to 6 different consumer objects. Though one could author code to perform
the buffering and delegation, the simplest solution is the ChannelSwitch
.
|
Figure 10: ChannelSwitch Overview
|
ChannelSwitch
offers AddDefaultRoute(BufferedTransformation&
destination)
function to add a destination. HashFilter
derives
from BufferedTransformation:
![]() |
Figure 11: HashFilter Inheritance
|
The abbreviated use of the ChannelSwitch
object in the Create Checksum
Shell Extension DLL is depicted below.
|
Figure 12: CreateChecksum DLL ChannelSwitch
|
An abridged use of the ChannelSwitch
object in the Verify Checksum
Shell Extension DLL is depicted below.
|
Figure 13: VerifyChecksum DLL ChannelSwitch
|
The code to accomplish multiple hashing based on a ChannelSwitch
is shown below. Two hashes are created: MD5 and SHA-1. Wei provides the sample code
in test.cpp of the Crypto++ library.
#include "channels.h" // ChannelSwitch
#include "filters.h" // HashFilter
#include "hex.h" // HexEncoder
#include "md5.h" // MD5
#include "sha.h" // SHA-1, SHA-256, SHA-512
int main( )
{
MD5 hashMD5;
SHA1 hashSHA1;
HashFilter filterMD5(hashMD5);
HashFilter filterSHA1(hashSHA1);
std::auto_ptr<ChannelSwitch> channel(new ChannelSwitch );
channel->AddDefaultRoute(filterMD5);
channel->AddDefaultRoute(filterSHA1);
...
}
Earlier, fciv.exe (KB
841290) was mentioned which creates and verifies MD5 and SHA-1 checksums. By
changing the StringSource
to a FileSource
, the reader
could have a new and improved fciv.exe less the XML encoding.
The output of the Sample 4 (using MD5, SHA-1, RIPEMD-160, and SHA-256) is shown below.
|
Figure 14: Sample 4
|
Command Line Debugging
If debugging using Visual Studio is too difficult or inconvenient, cdb.exe can be used. It is the command line equivalent of WinDbg. CDB can be downloaded from Microsoft in the Debugging Tools for Windows package. Some of the more useful commands for this exercise are shown below.
Attaching to Explorer
To attach to Windows Explorer, issue cdb -pid < pid>
, where
pid
is the process identification number of Explorer. Once attached, Explorer
will be suspended since the debugger is awaiting input. Enter g
to
run.
![]() |
Figure 15: Attach To Explorer
|
When Explorer is running, enter CTRL-C to break back into the debugger.
Once finished in the debugger, press g
again. Finally, ALT-Tab
does work with Explorer suspended. It will be useful in getting the debugger window
forward when Explorer cannot repaint (and is hiding a view).
Frozen Explorer or Debugger
This section is reiterated from above since it is so important. If Explorer is
frozen when attempting to work on the desktop, type g
in the debugger.
If the debugger is not the windows with focus, use ALT-Tab to bring the
debugger forward. Finally, if you cannot enter commands into the debugger, enter
CTRL-C to break.
Loaded Modules
Once attached to Explorer, we need to know if our DLL is loaded so we can determine
the breakpoint location and set the breakpoint. We can issue a load (ld
)
specify a full path name, of right click a file to coax Explorer into loading it.
Breakpoints
Issuing x ctx*!*hash*
will display symbol locations the two DLLs.
The final expression (*hash*
) refines the results. This is too much
information, since Crypto++ is full of symbols such as these.
To further refine the location search, issue x ctx*!*querycontextmenu
.
Now that the location is known, issue the breakpoint. Exercise Explorer. bl
lists breakpoints. When the breakpoint fires, enter p
once to step out
of DebugBreak()
and into the function. To step into a function, enter
t
.
![]() |
Figure 16: Locating Functions of
Interest
|
Managing an Unstable Windows Explorer
This portion of the article is again based on Michael Dunn's Guide to Writing Shell Extensions, Part I. Should the reader find the treatment too superficial, please refer the Michael's article. Michael details topics such as preparing the Windows environment for debugging Windows Explorer to allowing the Context Menu DLL to execute in light of Group Policy.
Before debugging, kill the Explorer process. When prompted for a Debug Executable, specify C:\Windows\Explorer.exe. When debugging begins, Visual Studio will start an instance of Explorer.
|
Figure 17: explorer.exe
|
Save your work frequently. Most problems only required restarting Explorer, or an occasional soft reboot. To restart Explorer, open Task Manager and End the Explorer process.
|
Figure 18: End Explorer Process
|
Next, switch to the Task tab, and click New Task.
|
Figure 19: New explorer.exe Task
|
If the reader builds the DLL, but the DLL cannot be opened to be written during linking, verify no instances of Explorer.exe are running. If no instances are present, restart Explorer.
|
Figure 20: Explorer Instances
|
Character Set Considerations
The Context Menu DLLs are written using wide characters since the NT family is dominating the landscape. The Crypto++ library is narrow, and the Windows API can be either.
|
Figure 21: Checksum DLL Design Overview
|
Data transfer with respect to Crypto++ is generally from Crypto++ to the DLL.
To facilitate the transfer, the DLL calls StringWiden()
on the narrow
data from Crypto++.
The same is not true for the Windows API. If _UNICODE
and
UNICODE
are defined, no conversion takes place. When using SBCS
and MBCS
, StringWiden()
and StringNarrow()
are employed when moving strings between Windows and the DLL.
The conversions will be handled by way of the standard c++ library's widen()
and narrow()
. Those using Visual C++ 7.0 and above have more flexibility
in use of standard library conversion routines.
// Courtesy of Tom Widmer (VC++ MVP)
std::wstring StringWiden( const std::string& narrow ) {
std::wstring wide;
wide.resize( narrow.length() );
typedef std::ctype<wchar_t> CT;
CT const& ct = std::_USE(std::locale(), CT);
// Non Portable
// Iterators should not be used as pointers (works in VC++ 6.0)
// wideness( narrow.begin(), narrow.end(), wide.begin() );
// Portable
// ct.widen(&narrow[0], &narrow[0] + narrow.size(), &wide[0]);
// Portable
ct.widen(narrow.data(), narrow.data() + narrow.size(), wide.data());
return wide;
}
Create and Verify Routines
Sample 4 (Channel Switch) and Sample 5 (CtxTest
) provides most of
the code required for the DLL. This section will discuss the remaining items of
interest. The create and verify routines share common code. This would include populating
the list of files and the Fly By help.
Initialize
Initialize()
has been expanded as follows. Notes that files
is a vector of wide string
. Once all of the files have been extracted,
the vector is sorted based on name.
STDMETHODIMP CCreateHash::Initialize( LPCITEMIDLIST pidlFolder,
LPDATAOBJECT pDataObj, HKEY hProgID )
{
pidlFolder; // Suppress Warning C4100
hProgID; // Suppress Warning C4100
FORMATETC fmt = { CF_HDROP,NULL,DVASPECT_CONTENT,-1,TYMED_HGLOBAL };
STGMEDIUM stg = { TYMED_HGLOBAL };
HDROP hDrop;
...
// Sanity check - make sure there is at least one filename.
UINT uNumFiles = DragQueryFile( hDrop,
static_cast<UINT>(-1), NULL, 0 );
if( 0 == uNumFiles )
{ return E_INVALIDARG; }
HRESULT hr = S_OK;
// The author has encountered situations where
// MAX_PATH was a bit too small...
TCHAR file[ MAX_PATH * 2 + 1 ];
// Loop through all the files that were selected.
for(UINT i = 0; i < uNumFiles; i++)
{
DragQueryFile( static_cast<HDROP>( stg.hGlobal ),
i, file, MAX_PATH * 2 );
// If the file name is a directory, silently skip
// We should not encounter this...
if (::GetFileAttributes( file ) & FILE_ATTRIBUTE_DIRECTORY)
{ continue; }
// Add the file name to the end of the list.
#ifdef UNICODE
files.push_back( file );
#else
files.push_back( StringWiden( file ) );
#endif
}
std::sort( files.begin(), files.end() );
return hr;
}
Create InvokeCommand
HRESULT CCreateHash::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )
{
// If lpVerb really points to a std::string,
// ignore this function call and bail out.
if ( 0 != HIWORD( pCmdInfo->lpVerb ) ) { return E_INVALIDARG; }
unsigned int i = 0, j = 0;
// Friendly Name: 'MD5'
std::vector< std::wstring > hashnames;
// Hash: 47FD4214F5775826FB20FEC1091987A1
std::vector< std::wstring > hashvalues;
std::wstring ClipboardText;
std::wstring MsgBoxMessage;
MsgBoxMessage = L"The following was placed on the Windows Clipboard:\r\n\r\n";
// We must look for Command 1 now
switch( LOWORD( pCmdInfo->lpVerb ) )
{
case 1:
{
for( i = 0; i < files.size(); i++ )
{
CalculateFileHashes( files[ i ], hashnames, hashvalues );
ClipboardText += FileName( files[ i ] ) + L"\r\n";
MsgBoxMessage += FileName( files[ i ] ) + L"\r\n";
for( j = 0; j < hashvalues.size(); j++ )
{
// Clipboard Text is easy...
// Just dump the information
ClipboardText += hashnames[ j ] + L": " + hashvalues[ j ] + L"\r\n";
...
} // End - Keep the Message Box size reasonable
} // for( j = 0; j < hashnames.size(); j++ )
// Pretty Print
if( i + 1 < files.size() )
{
ClipboardText += L"\r\n";
if( files.size() <= 2 )
{
MsgBoxMessage += L"\r\n";
} // for( i = 0; i < files.size(); i++ )
SetClipboardText( pCmdInfo->hwnd, ClipboardText );
#ifdef _UNICODE
MessageBox( pCmdInfo->hwnd, MsgBoxMessage.c_str(),
_T("File Checksum Results"), MB_ICONINFORMATION );
#else
MessageBox( pCmdInfo->hwnd, StringNarrow( MsgBoxMessage ).c_str(),
_T("File Checksum Results"), MB_ICONINFORMATION );
#endif
return S_OK;
break;
}
default:
break;
}
return E_INVALIDARG;
}
Verify InvokeCommand
Verify Checksum InvokeCommand()
uses the same basic code and logic
as Create Checksum. The difference in this code is the introduction of two additional
vectors: vector< wstring > verifiedfiles
and vector< wstring
> unverifiedfiles
for book keeping.
HRESULT CVerifyHash::InvokeCommand ( LPCMINVOKECOMMANDINFO pCmdInfo )
{
unsigned int i = 0, j = 0;
UINT style = MB_ICONINFORMATION;
bool found = false;
wstring ClipboardText;
wstring MsgBoxMessage;
vector< wstring > hashnames;
vector< wstring > hashvalues;
vector< wstring > verifiedfiles;
vector< wstring > verifiedhashes;
vector< wstring > unverifiedfiles;
// If lpVerb really points to a std::string,
// ignore this function call and bail out.
if ( 0 != HIWORD( pCmdInfo->lpVerb ) ) { return E_INVALIDARG; }
HWND hwnd = pCmdInfo->hwnd;
// If there is no text on the Clipboard,
// inform the user and bail out.
if( false == GetClipboardText( ClipboardText ) )
{
MessageBox( hwnd, _T("There is not text on the Clipboard."),
_T("File Checksum Verifier"), MB_ICONWARNING );
return S_OK;
}
// We must respond to Command 1 now.
switch( LOWORD( pCmdInfo->lpVerb ) )
{
case 1:
{
for( i = 0; i < files.size(); i++ )
{
// Hash found on the Clipboard?
found = false;
CalculateFileHashes( files[ i ], hashnames, hashvalues );
// Start at size(): this has the effect of
// verifying strongest (SHA-256) to weakest (MD4)
for( j = 0; j < hashvalues.size() ; j++ )
{
if( true == Find( hashvalues[ j ], ClipboardText ) )
{
found = true;
verifiedfiles.push_back( files[ i ] );
// Concatenate 'MD5: ' and
// '82A80BE6F1E0E7766FAC3CA661089EE4', etc
verifiedhashes.push_back( hashnames[ j ] + L": " +
Snip( hashvalues[ j ] ) );
j = hashvalues.size(); // Break the loop
}
} // for( j = 0; j < hashvalues.size(); j++ )
if( false == found )
{
unverifiedfiles.push_back( files[ i ] );
}
} // for( i = 0; i < files.size(); i++ )
...
return S_OK;
break;
}
default:
break;
}
return E_INVALIDARG;
}
This version of InvokeCommand()
maintains parallel arrays for simplicity.
The arrays are created for each file in the files
vector. The arrays
can be visualized as follows.
![]() |
Figure 22: Hash Name - Hash Value
Parallel Array
|
The arrays are created with CreateFileHashes()
. The function prototype
is below. Both Create and Verify use the function. Create simply dumps it to the
Clipboard, while Verify walks the hashvalues vector (from strongest to weakest),
searching for the hash value on the Clipboard.
bool CalculateFileHashes( const std::wstring& filename,
std::vector< std::wstring >& hashnames,
std::vector< std::wstring >& hashvalues )
InvokeCommand()
is now presented below. Most of the logic is dominated
by maintaining two strings - one for the Message Box, and the other for the Clipboard.
Recall that the extra code for the Message Box is required to keep the size of the
Message Box manageable.
Miscellaneous
When choosing a hash, one should choose at least a 160 bit hash. Note that hash length does not necessarily equate to strength. For example, RIPEMD-128 is as cryptographically strong as RIPEMD-256; RIPEMD-160 is as cryptographically strong as RIPEMD-320. RIPEMD-256 and RIPEMD-320 simply generate more entropy for a given Message M. The reader should refer to Optional Extensions to 256 and 320 Hash Results: RIPEMD-256 and RIPEMD-320 for details.
Taking from the NIST Website:
There are five (5) FIPS-approved algorithms for generating a condensed representation of a message (message digest): SHA-1, SHA-224, SHA-256, SHA-384, and SHA-512
March 15, 2006: The SHA-2 family of hash functions (i.e., SHA-224, SHA-256, SHA-384 and SHA-512) may be used by Federal agencies for all applications using secure hash algorithms. Federal agencies should stop using SHA-1 for digital signatures, digital time stamping and other applications that require collision resistance as soon as practical, and must use the SHA-2 family of hash functions for these applications after 2010. After 2010, Federal agencies may use SHA-1 only for the following applications: hash-based message authentication codes (HMACs); key derivation functions (KDFs); and random number generators (RNGs). Regardless of use, NIST encourages application and protocol designers to use the SHA-2 family of hash functions for all new applications and protocols.
Finally, taking from the RIPE MD website:
A 128-bit hash result does not offer sufficient protection anymore. A brute force collision search attack on a 128-bit hash result requires 264 or about 2 x 1019 evaluations of the function. In 1994 Paul van Oorschot and Mike Wiener showed that this brute-force job can be done in less than a month with a $10 million investment ("Parallel Collision Search with Applications to Hash Functions and Discrete Logarithms," 2nd ACM Conference on Computer and Communications Security, ACM Press, 1994, pp. 210-218). This cost is expected to halve every 18 months.
Visual Sudio 2005 and Platform SDK
Should the reader encounter the following issue during compilation:
error C2787: 'IContextMenu' : no GUID has been associated with this object
The reader can add the following to stdafx.h:
#ifndef IContextMenu
struct __declspec(uuid("000214e4-0000-0000-c000-000000000046")) IContextMenu;
#endif
Doug Harrison, Microsoft MVP, has additional fixes outlined in Missing IContextMenu.
Summary
File checksums are an often overlooked Cryptographic tool. With these DLLs, one can easily incorporate the Checksum functionality into his or her documents or website.
Downloads
- Download Compiled Shell Extension Dll - Create Checksum - 112 Kb
- Download Compiled Shell Extension Dll - Verify Checksum - 97 Kb
- Download Microsoft Visual C++ 2008 Redistributable Package
- Download Source Code - Shell Extension Dll - Create Checksum - 21 Kb
- Download Source Code - Shell Extension Dll - Verify Checksum - 29 Kb
- Download Source Code - Sample 1 - Enumerating Clipboard Data - 3.3 Kb
- Download Source Code - Sample 2 - Retrieving Clipboard Text - 2.9 Kb
- Download Source Code - Sample 3 - Writing Clipboard Unicode Text - 3.2 Kb
- Download Source Code - Sample 4 - Hashing Using the ChannelSwitch Class - 5.7 Kb
- Download Source Code - Sample 5 - Sample Shell Extension Dll - 11.5 Kb
Acknowledgments
- Wei Dai for Crypto++ and his invaluable help on the Crypto++ mailing list
- Dr. Brooke Stephens who laid my Cryptographic foundations
Revisions
- 05.24.2008 Added Vista regsvr32.exe Error
- 05.24.2008 Tested Upgrade to Visual C++ 9.0 (VS2008)
- 03.07.2008 Added VS2008 regsvr32.exe Error
- 12.01.2007 Added Windows XP and Above Composting Issue
- 08.03.2007 Added note on IContextMenu and Visual Studio 2005
- 08.03.2007 Upgraded from Visual C++ 7.1 to Visual C++ 8.0
- 05.31.2007 Upgraded from Visual C++ 6.0 to Visual C++ 7.1
- 05.31.2007 Verified Compatibility with Crypto++ 5.5.1
- 05.31.2007 Removed HAVAL in CtxVerifyHash.dll
- 05.31.2007 Added Additional SHA-2 Hashes in CtxVerifyHash.dll
- 05.31.2007 Added Whirlpool (512) Hash in CtxVerifyHash.dll
- 01.09.2007 Added Reference to NIST Hash Choices
- 12.19.2006 Added Section Crypto++ String and File Hashing
- 12.17.2006 Added CRC32 to Verify Shell Extension DLL
- 12.16.2006 Update Article Graphics
- 12.15.2006 Updated ChannelSwitch
- 12.14.2006 Initial Release
Checksums
- CtxCreateHash.zip
- MD5: D967CF24BEC8BF403B0F274B7908876E
- RIPEMD-128: CF073CB397C912EE3395C63F5CCF93FE
- RIPEMD-160: 324123B69596608381147F0F60C343B3F5C4B007
- RIPEMD-256: 5A5A18771EAAF7A2E60C83D2FC8EC507389532A1E7F80FD2C38D5E949899A07F
- RIPEMD-320: C8A01A5A8BA0323CEB25DA4FC45E155E47ACC5BFF7481AECF0C1E4250E5CF07DF7885A9CFD3D8E23
- SHA-1: 53CFD2F493846CC49EC5209CA7E4C9939D371172
- SHA-224: 70A8F1066BEAE431E4462E226A4293DB323A096EDE5163A47B83E64C
- SHA-256: 75DA22C742752DBC73AB421F8A48BCCEC4BDF5486DFF16EB9395C6F499DF9221
- CtxCreateHashDll.zip
- RIPEMD-128: ABEF419E395A7A21CE9D65A5419842D4
- RIPEMD-160: 22EF853EAE308F7B07CA674CC50BE6D9929F3649
- RIPEMD-256:
- 19CC4D1BFD0B92B9E7D48CB7CE14C0C3F094E8E15EC8EB61C89632C5032D474C
- RIPEMD-320: D06012A5A9EA47436AFD247B90D179081B64C62CEF3BA20DF35DB85021FFBB386BA7962A289BB224
- CtxVerifyHash.zip
- SHA-1: B54562A1EC047F31C75027C396CE44DFE6F2020D
- SHA-224: CB413BAD801E4C9F8043BAF294FA29F0616F449B42E453B9EE1E5941
- SHA-256: D10E2C892487CC6A17D5C673DE52974F7F0DB701342DD46B1821FD479DBCEC4F
- CtxVerifyHashDll.zip
- RIPEMD-256: 82BC7E086B8EDA7C1A8C5310F82F31DDEA13BF192482A6D1F362831E8FC2F23A
- SHA-256: 1602BD0FF62E05F4B77428C5943FE37CB7CCE6367C5D79CCC004E125A2C6266A
- Sample1.zip
- CRC32: BD50E874
- Sample2.zip
- MD5: 0CAE59412D3272C12A4985930F313DC1
- Sample3.zip
- SHA-1: 68274EDD7A70792057A379048F1FBA6E58048F7E
- Sample4.zip
- RIPEMD-160: 7434F4A3498A642A53FCC3AF6081718BE18FCE28
- Sample5.zip
- SHA-256: 3DA6D8C6D29DE726B96838273C5E9D7C558F725BF6574345C054E7FD1325DF42