65.9K
CodeProject 正在变化。 阅读更多。
Home

文件哈希生成器 Shell 扩展

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.55/5 (11投票s)

2008年4月10日

CPOL

4分钟阅读

viewsIcon

87546

downloadIcon

1815

描述了一个 Shell 扩展选项,用于计算文件的文件哈希(SHA-1、MD5 等),以验证其真实性。

FileHash.png

目录

引言

文件哈希用于验证文件的真实性和完整性——尤其是在通过互联网传输的文件。例如,当从 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 的路径是否适合您的环境)。
© . All rights reserved.