文件校验和 Shell 菜单扩展 DLL






4.89/5 (32投票s)
使用 ATL 和 Crypto++ 创建文件校验和 Shell 菜单扩展。
简介
文件校验和用于验证文件的完整性。校验和可以检测传输错误和篡改。要检测传输错误,我们可以使用 CRC(循环冗余校验)[1]。要检测篡改,我们通常会选择一种加密 哈希,因为其具有抗碰撞性的理想特性 [2]。
本文介绍了两个 Shell 扩展 DLL,它们可用于创建文件校验和和验证文件校验和。本文基于 Michael Dunn 的《编写 Shell 扩展指南,第一部分》[4]、Tom Archer 的《使用剪贴板,第一部分:传输简单文本》[5] 和 Crypto++。本文将讨论以下主题:
- Shell 扩展 DLL 用法
- 编译和集成Crypto++
- Windows 剪贴板 API
- 创建 Shell 上下文菜单扩展 DLL
- Crypto++ ChannelSwitch 类
- 命令行调试
- 管理不稳定的 Windows Explorer
- 字符集注意事项
- 创建和验证例程
- 杂项
- Visual Studio 2005 和 Platform SDK
Microsoft 提供了一个命令行文件校验和工具,该工具发布在知识库文章 Q841290 文件校验和完整性验证程序实用工具的可用性和描述 [6]。Microsoft 工具支持 MD5 和 SHA1。
Shell 扩展 DLL 用法
如果读者希望使用扩展 DLL,应按照下文所述进行下载和安装。DLL 注册后,当用户在 Windows Explorer 中右键单击文件(或多个文件)时,它们将作为上下文菜单可用。
- 下载 DLL
- CtxCreateHashDll.zip
- CtxVerifyHashDll.zip
- 解压到 C:\Windows\System\
- 注册 DLL
regsvr32.exe C:\Windows\System\CtxCreateHash.Dll
regsvr32.exe C:\Windows\System\CtxVerifyHash.Dll
Windows Vista 和用户帐户控制
要在启用了用户帐户控制的情况下在 Vista 上手动运行 regsvr32.exe,请从“开始”菜单导航到命令提示符。右键单击命令提示符并选择“以管理员身份运行”,如图 1 所示。
![]() |
图 1:以管理员身份运行
|
如果不以提升的权限运行 regsvr32,通常会导致错误“DllRegisterServer 失败,错误代码为 0x80070005”,而成功则会显示熟悉的成功消息,如下所示。
![]() |
图 2:DllRegisterServer 成功
|
Visual C++ 运行时
编译的 DLL 的最新版本使用 Visual Studio 2008 构建和链接。如果需要,请下载 Microsoft Visual C++ 2008 可再发行组件包。需要该程序包的一个典型示例如 regsvr32 无法注册 DLL 导致错误“由于应用程序配置不正确,应用程序失败。重新安装应用程序可能可以解决此问题”。
校验和创建
选择文件或多个文件后,如果用户选择“创建校验和”,则会创建以下哈希并将它们放到剪贴板上:
- MD5
- RIPE MD-128, RIPE MD-160, RIPE MD-256, RIPE MD-320
- SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
- Whirlpool
然后会显示一个消息框,其中包含哈希文件或文件的摘要。为了使消息框的大小可控,将显示截断的版本。
|
图 3:截断的消息框
|
完整的校验和会放入 Windows 剪贴板以供粘贴。从剪贴板粘贴到记事本将显示完整的文本。
|
图 4:剪贴板文本
|
校验和验证
验证文件的校验和同样简单。导航到校验和所在网页或文档,高亮显示并复制到剪贴板。
|
图 5:将校验和复制到剪贴板
|
导航到文件,选择,右键单击,然后选择“验证校验和”。
|
图 6:验证校验和
|
支持的验证算法有:
- 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
将显示一个类似如下的消息框。消息框会将文件分为两类:已验证和未验证。已验证的文件将显示“已验证校验和”消息和校验和的摘要。未验证的文件将在“未验证校验和”标题下。
|
图 7:验证校验和消息框
|
验证时,DLL 会按从强到弱(SHA-512 到 CRC32)的顺序查找匹配的哈希值。匹配算法在第一次匹配时终止,因此只显示最强的哈希。
编译和集成 Crypto++
示例使用了各种 Crypto++ 对称加密算法。Crypto++ 可以从 Wei Dai 的 Crypto++ 页面下载。有关编译和集成问题,请访问《将 Crypto++ 集成到 Microsoft Visual C++ 环境中》。本文基于先前文章中提出的基本假设。对于那些对其他 C++ 加密库感兴趣的人,请参阅 Peter Gutmann 的Cryptlib 或 Victor Shoup 的NTL。
Windows 剪贴板 API
请参阅 Tom Archer 的《使用剪贴板,第一部分:传输简单文本》,了解有关该主题的深入讨论。示例 1 演示了枚举剪贴板的数据格式。示例 2 演示了从剪贴板读取文本。最后,示例 3 演示了向剪贴板写入 Unicode 文本。
|
图 8:写入剪贴板文本
|
创建 Shell 上下文菜单扩展 DLL
创建 Shell 上下文菜单主要基于 Michael Dunn 的《编写 Shell 扩展指南,第一部分》。有关讨论,请参阅 Michael 的文章。Michael 的技术非常适合为 Windows 2000 插入单个菜单项或多个菜单项。
组合
与 Michael 的文章不同,在 Windows XP、Server 2003 和 Vista 上调用 InsertMenu
时,我们需要使用一种略有不同的技术。这是由于组合。组合是 Windows XP 及更高版本用于将上下文菜单项分组的技术。在图 9 中,我们看到组合的两个示例。Adobe 提供了两个 DLL,它们被分组在一起,校验和 DLL 也被分组在一起。
![]() |
图 9:组合
|
有关组合的讨论,请参阅 Raymond Chen 关于《The Old New Thing》的文章系列。感兴趣的两个章节是《第 10 章:复合扩展 - 基础》和《第 11 章:复合扩展 - 组合》。请注意,Chen 的示例代码是从 Shell 的角度呈现的,而不是我们的角度。由于 Windows XP、Server 2003 和 Vista 中组合的副作用,我们必须按如下方式插入菜单项:
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 );
如果我们添加两个菜单项,我们的例程将如下所示:
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 );
Shell 用来确定哪些项目应被组合(以及如何排列)的算法是不可用的。但似乎它取决于:
- DLL 的注册表字符串名称
- 字符串比较中匹配的前导字符数
似乎该算法位于 Shell 的 Shell32!_imp__DSA_InsertItem
函数中。观察到的经验法则是,如果注册表字符串中有两个或更多字符匹配,则项目将被组合。
Crypto++ ChannelSwitch 类
从磁盘多次读取可能会成为性能瓶颈。如果我们连续读取同一个文件,情况尤其如此。为了克服多次磁盘读取的问题,可以使用 Crypto++ ChannelSwitch
类。ChannelSwitch
类允许用户在单次磁盘读取后将数据流式传输到多个基于 HashFilter
的对象。更准确地说,可以将数据推送到任何 BufferedTransformation
派生对象。在执行字符串(内存中)操作时,这很简单;但基于磁盘的操作会影响响应时间。用户不想读取 1 MB 的文件 6 次以将其发送到 6 个不同的使用者对象。尽管可以编写代码来执行缓冲和委托,但最简单的解决方案是 ChannelSwitch
。
|
图 10:ChannelSwitch 概述
|
ChannelSwitch
提供 AddDefaultRoute(BufferedTransformation& destination)
函数来添加目标。HashFilter
派生自 BufferedTransformation
:
![]() |
图 11:HashFilter 继承
|
Create Checksum Shell Extension DLL 中 ChannelSwitch
对象的简要用法如下所示。
|
图 12:CreateChecksum DLL ChannelSwitch
|
Verify Checksum Shell Extension DLL 中 ChannelSwitch
对象的简要用法如下所示。
|
图 13:VerifyChecksum DLL ChannelSwitch
|
下面显示了使用 ChannelSwitch
进行多个哈希处理的代码。创建了两个哈希:MD5 和 SHA-1。Wei 在 Crypto++ 库的test.cpp中提供了示例代码。
#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);
...
}
前面提到了 fciv.exe(KB 841290),它创建和验证 MD5 和 SHA-1 校验和。通过将 StringSource
更改为 FileSource
,读者可以获得一个新改进的 fciv.exe,但缺少 XML 编码。
下面显示了示例 4(使用 MD5、SHA-1、RIPEMD-160 和 SHA-256)的输出。
|
图 14:示例 4
|
命令行调试
如果使用 Visual Studio 进行调试太困难或不方便,可以使用 cdb.exe。它是 WinDbg 的命令行版本。CDB 可以从 Microsoft 的Debugging Tools for Windows 包下载。本练习中一些更有用的命令如下所示。
附加到 Explorer
要附加到 Windows Explorer,请发出 cdb -pid < pid>
命令,其中 pid
是 Explorer 的进程标识号。附加后,Explorer 将被挂起,因为调试器正在等待输入。输入 g
运行。
![]() |
图 15:附加到 Explorer
|
当 Explorer 运行时,按 CTRL-C 切换回调试器。在调试器中完成后,再次按 g
。最后,ALT-Tab 在 Explorer 挂起时仍然有效。这对于将调试器窗口置于最前面很有用,尤其是在 Explorer 无法重绘(并且隐藏了某个视图)的情况下。
冻结的 Explorer 或调试器
由于此部分非常重要,因此从上面重申。如果在尝试处理桌面时 Explorer 冻结,请在调试器中键入 g
。如果调试器不是具有焦点的窗口,请使用 ALT-Tab 将调试器带到最前面。最后,如果您无法在调试器中输入命令,请按 CTRL-C 中断。
加载的模块
附加到 Explorer 后,我们需要知道我们的 DLL 是否已加载,以便确定断点位置并设置断点。我们可以发出 ld
命令,指定一个完整路径名,或者右键单击一个文件来促使 Explorer 加载它。
断点
发出 x ctx*!*hash*
将显示两个 DLL 的符号位置。最后一个表达式(*hash*
)细化了结果。这信息量太大,因为 Crypto++ 包含许多此类符号。
为了进一步细化位置搜索,请发出 x ctx*!*querycontextmenu
。现在已知位置,请设置断点。运行 Explorer。bl
列出断点。当断点触发时,输入 p
一次以从 DebugBreak()
步出并进入函数。要进入一个函数,请键入 t
。
![]() |
图 16:定位感兴趣的函数
|
管理不稳定的 Windows Explorer
本文的这部分再次基于 Michael Dunn 的《编写 Shell 扩展指南,第一部分》。如果读者觉得处理过于肤浅,请参考 Michael 的文章。Michael 详细介绍了准备 Windows 环境以调试 Windows Explorer 的主题,以及允许上下文菜单 DLL 在组策略下执行。
调试前,请终止 Explorer 进程。当提示输入 Debug Executable 时,请指定 C:\Windows\Explorer.exe。调试开始时,Visual Studio 将启动一个 Explorer 实例。
|
图 17:explorer.exe
|
经常保存您的工作。大多数问题只需要重新启动 Explorer,或者偶尔进行软重启。要重新启动 Explorer,请打开任务管理器并终止 Explorer 进程。
|
图 18:终止 Explorer 进程
|
接下来,切换到“任务”选项卡,然后单击“新建任务”。
|
图 19:新的 explorer.exe 任务
|
如果读者编译了 DLL,但在链接时无法打开 DLL 进行写入,请验证没有运行 Explorer.exe 实例。如果不存在实例,请重新启动 Explorer。
|
图 20:Explorer 实例
|
字符集注意事项
上下文菜单 DLL 使用宽字符编写,因为 NT 系列在当前占据主导地位。Crypto++ 库是窄的,而 Windows API 可以是两者的任意一种。
|
图 21:校验和 DLL 设计概述
|
与 Crypto++ 相比,数据传输通常是从 Crypto++ 到 DLL。为了方便传输,DLL 对来自 Crypto++ 的窄数据调用 StringWiden()
。
Windows API 的情况则不同。如果定义了 _UNICODE
和 UNICODE
,则不进行转换。在使用 SBCS
和 MBCS
时,在 Windows 和 DLL 之间移动字符串时会使用 StringWiden()
和 StringNarrow()
。
转换将通过标准 C++ 库的 widen()
和 narrow()
来处理。使用 Visual C++ 7.0 及更高版本的用户在使用标准库转换例程方面具有更大的灵活性。
// 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;
}
创建和验证例程
示例 4(Channel Switch)和示例 5(CtxTest
)提供了 DLL 所需的大部分代码。本节将讨论其余感兴趣的项目。创建和验证例程共享通用代码。这包括填充文件列表和 Fly By 帮助。
初始化
Initialize()
已按如下方式扩展。请注意,files
是一个宽 string
的向量。提取完所有文件后,将根据名称对向量进行排序。
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()
使用与 Create Checksum 相同的基本代码和逻辑。此代码的区别在于引入了两个额外的向量:vector< wstring > verifiedfiles
和 vector< wstring > unverifiedfiles
用于簿记。
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;
}
此版本的 InvokeCommand()
为简单起见,维护着并行数组。这些数组是为 files
向量中的每个文件创建的。数组可视化如下:
![]() |
图 22:哈希名称 - 哈希值并行数组
|
数组是通过 CreateFileHashes()
创建的。函数原型如下。Create 和 Verify 都使用该函数。Create 仅将其转储到剪贴板,而 Verify 则遍历哈希值向量(从最强的到最弱的),在剪贴板上搜索哈希值。
bool CalculateFileHashes( const std::wstring& filename,
std::vector< std::wstring >& hashnames,
std::vector< std::wstring >& hashvalues )
现在显示 InvokeCommand()
。大部分逻辑由维护两个字符串主导——一个用于消息框,另一个用于剪贴板。请记住,消息框的额外代码是必需的,以保持消息框的大小可控。
杂项
选择哈希时,应选择至少 160 位哈希。请注意,哈希长度并不一定等同于强度。例如,RIPEMD-128 与 RIPEMD-256 一样具有加密强度;RIPEMD-160 与 RIPEMD-320 一样具有加密强度。RIPEMD-256 和 RIPEMD-320 仅为给定的消息 M 生成更多的熵。读者应参考可选的 256 和 320 哈希结果扩展:RIPEMD-256 和 RIPEMD-320 获取详细信息。
摘自NIST 网站
有五 (5) 种 FIPS 批准的算法用于生成消息的压缩表示(消息摘要):SHA-1、SHA-224、SHA-256、SHA-384 和 SHA-512。
2006 年 3 月 15 日:SHA-2 系列哈希函数(即 SHA-224、SHA-256、SHA-384 和 SHA-512)可供联邦机构用于所有使用安全哈希算法的应用程序。联邦机构应尽快停止使用 SHA-1 进行数字签名、数字时间戳和其他需要抗碰撞性的应用程序,并在 2010 年后必须使用 SHA-2 系列哈希函数进行这些应用程序。2010 年之后,联邦机构只能将 SHA-1 用于以下应用程序:基于哈希的消息身份验证码 (HMAC)、密钥派生函数 (KDF) 和随机数生成器 (RNG)。无论如何使用,NIST 都鼓励应用程序和协议设计者为所有新应用程序和协议使用 SHA-2 系列哈希函数。
最后,摘自RIPE MD 网站
128 位哈希结果不再提供足够的保护。对 128 位哈希结果进行暴力碰撞搜索攻击需要 264 次或约 2 x 1019 次函数求值。1994 年,Paul van Oorschot 和 Mike Wiener 表明,这项暴力破解工作可以在不到一个月的时间内完成,投资为 1000 万美元(“Parallel Collision Search with Applications to Hash Functions and Discrete Logarithms”,第 2 届 ACM 计算机与安全会议,ACM Press,1994 年,第 210-218 页)。预计此成本每 18 个月减半。
Visual Studio 2005 和 Platform SDK
如果在编译过程中遇到以下问题:
error C2787: 'IContextMenu' : no GUID has been associated with this object
读者可以在 stdafx.h 中添加以下内容:
#ifndef IContextMenu
struct __declspec(uuid("000214e4-0000-0000-c000-000000000046")) IContextMenu;
#endif
Microsoft MVP Doug Harrison 在Missing IContextMenu 中提供了其他修复方法。
摘要
文件校验和是一种经常被忽视的加密工具。有了这些 DLL,用户就可以轻松地将校验和功能集成到他们的文档或网站中。
下载
- 下载已编译的 Shell 扩展 DLL - 创建校验和 - 112 Kb
- 下载已编译的 Shell 扩展 DLL - 验证校验和 - 97 Kb
- 下载 Microsoft Visual C++ 2008 可再发行组件包
- 下载源代码 - 示例 1 - 枚举剪贴板数据 - 3.3 Kb
- 下载源代码 - 示例 2 - 检索剪贴板文本 - 2.9 Kb
- 下载源代码 - 示例 3 - 写入剪贴板 Unicode 文本 - 3.2 Kb
- 下载源代码 - 示例 4 - 使用 ChannelSwitch 类进行哈希处理 - 5.7 Kb
- 下载源代码 - 示例 5 - 示例 Shell 扩展 DLL - 11.5 Kb
致谢
- Wei Dai for Crypto++ 及其在 Crypto++ 邮件列表上的宝贵帮助
- Dr. Brooke Stephens,他为我奠定了加密基础。
修订
- 2008.05.24 添加了 Vista regsvr32.exe 错误
- 2008.05.24 测试了升级到 Visual C++ 9.0 (VS2008)
- 2008.03.07 添加了 VS2008 regsvr32.exe 错误
- 2007.12.01 添加了 Windows XP 及更高版本的组合问题
- 2007.08.03 添加了关于 IContextMenu 和 Visual Studio 2005 的注释
- 2007.08.03 从 Visual C++ 7.1 升级到 Visual C++ 8.0
- 2007.05.31 从 Visual C++ 6.0 升级到 Visual C++ 7.1
- 2007.05.31 验证了与 Crypto++ 5.5.1 的兼容性
- 2007.05.31 从 CtxVerifyHash.dll 中移除了 HAVAL
- 2007.05.31 在 CtxVerifyHash.dll 中添加了其他 SHA-2 哈希
- 2007.05.31 在 CtxVerifyHash.dll 中添加了 Whirlpool (512) 哈希
- 2007.01.09 添加了对 NIST 哈希选择的引用
- 2006.12.19 添加了“Crypto++ 字符串和文件哈希”部分
- 2006.12.17 在 Verify Shell Extension DLL 中添加了 CRC32
- 2006.12.16 更新了文章图形
- 2006.12.15 更新了 ChannelSwitch
- 2006.12.14 初始发布
校验和
- 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