文件哈希生成器 Shell 扩展






3.55/5 (11投票s)
描述了一个 Shell 扩展选项,用于计算文件的文件哈希(SHA-1、MD5 等),以验证其真实性。
目录
引言
文件哈希用于验证文件的真实性和完整性——尤其是在通过互联网传输的文件。例如,当从 MSDN 下载文件时,您会看到 SHA-1 哈希——看起来随机的字符和数字列表,它们是使用 SHA-1 加密算法生成的,用于唯一标识该文件。即使该文件的单个比特发生更改,哈希本身也会改变。最重要的是,几乎不可能创建另一个文件来生成相同的哈希,这使得伪造变得不可行。但问题仍然是,我如何轻松地将该哈希与我实际下载的文件进行比较?本文将介绍一个 Windows Shell 扩展,让您可以快速轻松地访问任何文件的哈希。
背景
本文涵盖了两个编码概念。第一个是加密哈希,第二个是 Windows Shell 扩展。加密哈希有许多不同的算法,它会生成文件的数字指纹。.NET Framework 提供了 6 种 System.Security.Cryptography.HashAlgorithm
实现,可用于生成数字指纹:MD5、SHA-1、SHA-256、SHA-384、SHA-512 和 RIPEMD-160。下载文件时最常用的两个是 MD5 和 SHA-1。Windows Shell 扩展将我们带出托管代码的舒适区,迫使我们实现 COM 来集成到 Win32 的非托管世界。为此实用程序的这一部分,代码直接摘自 Dino Esposito 的文章 使用 Windows Shell 进行管理:使用 C# 编写 Shell 扩展。Dino 对 COM 接口和示例代码的解释对本项目来说是无价的。要真正理解 Shell 扩展的实现,我强烈推荐他的文章。
使用该实用工具
通过集成到 Windows 资源管理器上下文菜单,生成哈希就像选择一个或多个文件,然后右键单击显示上下文菜单一样简单。从该菜单中,您可以选择要生成的文件的哈希类型,方法是选择子菜单选项。然后,您将看到一个包含文件名、您选择的哈希以及您选择的文件(或文件)的完整路径的窗口。此 DataGridView 表允许选择所需的值并复制到剪贴板,如果您需要发布哈希值。就是这么简单!
代码审查
生成文件哈希是一项非常直接的任务。在下面的代码示例中,HashAlgorithm
抽象类型的特定实现是基于用户选择的 HashType
枚举值创建的。接下来,使用 System.IO.FileStream
对象打开文件,并将其流式传输到 HashAlgorithm
对象,让它发挥作用。然后,将生成的 Byte
数组放入 StringBuilder
,以便可以将哈希字符串返回给调用对象。
public static string GetFileHash(string filePath, HashType type) { if (!File.Exists(filePath)) return string.Empty; System.Security.Cryptography.HashAlgorithm hasher; switch(type) { case HashType.SHA1: default: hasher = new SHA1CryptoServiceProvider(); break; case HashType.SHA256: hasher = new SHA256Managed(); break; case HashType.SHA384: hasher = new SHA384Managed(); break; case HashType.SHA512: hasher = new SHA512Managed(); break; case HashType.MD5: hasher = new MD5CryptoServiceProvider(); break; case HashType.RIPEMD160: hasher = new RIPEMD160Managed(); break; } StringBuilder buff = new StringBuilder(); try { using (FileStream f = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)) { hasher.ComputeHash(f); Byte[] hash = hasher.Hash; foreach (Byte hashByte in hash) { buff.Append(string.Format("{0:x2}", hashByte)); } } } catch { return "Error reading file." + new System.Random(DateTime.Now.Second * DateTime.Now.Millisecond).Next().ToString(); } return buff.ToString(); } public enum HashType { [Description("SHA-1")] SHA1, [Description("SHA-256")] SHA256, [Description("SHA-384")] SHA384, [Description("SHA-512")] SHA512, [Description("MD5")] MD5, [Description("RIPEMD-160")] RIPEMD160 }
当您想在 Windows 资源管理器中右键单击文件并生成哈希时,诀窍就在这里。这就是 Dino Esposito 专业知识发挥作用的地方。通过修改他文章中的代码,我能够挂接到 Shell 上下文菜单,并添加我的菜单选项以及各种哈希类型的子菜单选择。此代码可以在示例项目中的 FileHashShellExt.cs 文件中找到。此集成的关键要素是
IContextMenu
接口。第一个方法 QueryContextMenu
,结合 shell32 的 DragQueryFile
方法,允许您询问所选文件的数量和类型,以确定是否应添加自定义菜单选项。第二个方法 InvokeCommand
提供有关所选子菜单项的信息,以便您可以执行正确的哈希类型。现在您的代码已准备就绪,您需要让 Windows 了解您的实用程序。这通过注册表处理。注册用于 COM 互操作的程序集很容易,但如何让 Windows 知道它究竟应该做什么呢?通过实现
System.Runtime.InteropServices.ComRegisterFunctionAttribute
属性以及 RegisterServer
方法。当您使用 regasm.exe 注册程序集以添加必要的注册表项时,此方法将被执行,这些注册表项会告诉 Windows Shell 接受新扩展并为所有文件显示上下文菜单选项。[System.Runtime.InteropServices.ComRegisterFunctionAttribute()] static void RegisterServer(String str1) { try { // For Winnt set me as an approved shellex RegistryKey root; RegistryKey rk; root = Registry.LocalMachine; rk = root.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved", true); rk.SetValue(guid.ToString(), "FileHash shell extension"); rk.Flush(); rk.Close(); // Set "*\\shellex\\ContextMenuHandlers\\BatchResults" regkey to my guid root = Registry.ClassesRoot; rk = root.CreateSubKey("*\\shellex\\ContextMenuHandlers\\FileHash"); rk.SetValue("", guid.ToString()); rk.Flush(); rk.Close(); } catch(Exception e) { System.Console.WriteLine(e.ToString()); } }有一个关联的方法
UnregisterServer
,当您使用 regasm.exe 和 "/u" 标志注销程序集时,它会被调用以删除注册表项。如果您通过演示项目的安装程序安装 Shell 扩展,所有这些都将被处理。如果您选择手动下载代码并进行安装,您可以分别使用 register.bat 和 unregister.bat 文件(您需要检查 regasm.exe 和 gacutil.exe 的路径是否适合您的环境)。