Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在C#中创建文件夹的哈希?_C#_Security - Fatal编程技术网

如何在C#中创建文件夹的哈希?

如何在C#中创建文件夹的哈希?,c#,security,C#,Security,我需要为包含一些文件的文件夹创建哈希。我已经为每个文件完成了这个任务,但我正在寻找一种方法,为文件夹中的所有文件创建一个哈希。有什么办法吗 (当然,我可以为每个文件创建散列,并将其连接到某个大散列,但这不是我喜欢的方式)将文件名和文件内容连接到一个大字符串中并进行散列,或者分块进行散列以提高性能 当然,您需要考虑以下几点: 您需要按名称对文件进行排序,以便在文件顺序发生更改时不会得到两个不同的哈希值 使用此方法时,只考虑文件名和内容。如果文件名不算数,您可以先按内容排序,然后进行散列。如果更多

我需要为包含一些文件的文件夹创建哈希。我已经为每个文件完成了这个任务,但我正在寻找一种方法,为文件夹中的所有文件创建一个哈希。有什么办法吗


(当然,我可以为每个文件创建散列,并将其连接到某个大散列,但这不是我喜欢的方式)

将文件名和文件内容连接到一个大字符串中并进行散列,或者分块进行散列以提高性能

当然,您需要考虑以下几点:

  • 您需要按名称对文件进行排序,以便在文件顺序发生更改时不会得到两个不同的哈希值
  • 使用此方法时,只考虑文件名和内容。如果文件名不算数,您可以先按内容排序,然后进行散列。如果更多属性(ctime/mtime/hidden/CARVIED..)很重要,请将它们包含在待散列的字符串中

如果您已经为所有文件设置了哈希,只需按字母顺序对哈希进行排序,将它们连接起来,然后再次对它们进行哈希,即可创建uber哈希

创建文件的tarball,散列tarball

> tar cf hashes *.abc
> md5sum hashes
或者将单个文件散列并将输出管道化为散列命令

> md5sum *.abc | md5sum
编辑:上述两种方法都不会对文件进行排序,因此每次调用可能会返回不同的哈希值,具体取决于shell如何展开星号。

这将哈希所有文件(相对)路径和内容,并正确处理文件顺序

对于4MB的目录,它的速度就像30ms

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;

...

public static string CreateMd5ForFolder(string path)
{
    // assuming you want to include nested folders
    var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
                         .OrderBy(p => p).ToList();

    MD5 md5 = MD5.Create();

    for(int i = 0; i < files.Count; i++)
    {
        string file = files[i];

        // hash path
        string relativePath = file.Substring(path.Length + 1);
        byte[] pathBytes = Encoding.UTF8.GetBytes(relativePath.ToLower());
        md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);

        // hash contents
        byte[] contentBytes = File.ReadAllBytes(file);
        if (i == files.Count - 1)
            md5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
        else
            md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
    }

    return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower();
}
public static string CreateDirectoryMd5(string srcPath)
{
    var filePaths = Directory.GetFiles(srcPath, "*", SearchOption.AllDirectories).OrderBy(p => p).ToArray();

    using (var md5 = MD5.Create())
    {
        foreach (var filePath in filePaths)
        {
            // hash path
            byte[] pathBytes = Encoding.UTF8.GetBytes(filePath);
            md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);

            // hash contents
            byte[] contentBytes = File.ReadAllBytes(filePath);

            md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
        }

        //Handles empty filePaths case
        md5.TransformFinalBlock(new byte[0], 0, 0);

        return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower();
    }
}
使用系统;
使用系统文本;
使用System.Security.Cryptography;
使用System.IO;
使用System.Linq;
...
公共静态字符串CreateMd5ForFolder(字符串路径)
{
//假设要包括嵌套文件夹
var files=Directory.GetFiles(路径“***”,SearchOption.AllDirectories)
.OrderBy(p=>p.ToList();
MD5 MD5=MD5.Create();
对于(int i=0;i
邓克的答案很有效;但是,它不处理空目录。下面的代码返回空目录的MD5“d41d8cd98f00b204e9800998ecf8427e”(0长度字符流的MD5)

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Linq;

...

public static string CreateMd5ForFolder(string path)
{
    // assuming you want to include nested folders
    var files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
                         .OrderBy(p => p).ToList();

    MD5 md5 = MD5.Create();

    for(int i = 0; i < files.Count; i++)
    {
        string file = files[i];

        // hash path
        string relativePath = file.Substring(path.Length + 1);
        byte[] pathBytes = Encoding.UTF8.GetBytes(relativePath.ToLower());
        md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);

        // hash contents
        byte[] contentBytes = File.ReadAllBytes(file);
        if (i == files.Count - 1)
            md5.TransformFinalBlock(contentBytes, 0, contentBytes.Length);
        else
            md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
    }

    return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower();
}
public static string CreateDirectoryMd5(string srcPath)
{
    var filePaths = Directory.GetFiles(srcPath, "*", SearchOption.AllDirectories).OrderBy(p => p).ToArray();

    using (var md5 = MD5.Create())
    {
        foreach (var filePath in filePaths)
        {
            // hash path
            byte[] pathBytes = Encoding.UTF8.GetBytes(filePath);
            md5.TransformBlock(pathBytes, 0, pathBytes.Length, pathBytes, 0);

            // hash contents
            byte[] contentBytes = File.ReadAllBytes(filePath);

            md5.TransformBlock(contentBytes, 0, contentBytes.Length, contentBytes, 0);
        }

        //Handles empty filePaths case
        md5.TransformFinalBlock(new byte[0], 0, 0);

        return BitConverter.ToString(md5.Hash).Replace("-", "").ToLower();
    }
}

这里有一个解决方案,它使用流来避免内存和延迟问题

默认情况下,文件路径包含在哈希中,这不仅会考虑文件中的数据,还会考虑文件系统条目本身,从而避免哈希冲突。这篇文章被贴上了安全标签,所以这应该很重要

最后,这个解决方案让您控制哈希算法,哪些文件被哈希,以及以什么顺序

public static class HashAlgorithmExtensions
{
    public static async Task<byte[]> ComputeHashAsync(this HashAlgorithm alg, IEnumerable<FileInfo> files, bool includePaths = true)
    {
        using (var cs = new CryptoStream(Stream.Null, alg, CryptoStreamMode.Write))
        {
            foreach (var file in files)
            {
                if (includePaths)
                {
                    var pathBytes = Encoding.UTF8.GetBytes(file.FullName);
                    cs.Write(pathBytes, 0, pathBytes.Length);
                }

                using (var fs = file.OpenRead())
                    await fs.CopyToAsync(cs);
            }

            cs.FlushFinalBlock();
        }

        return alg.Hash;
    }
}
公共静态类HashAlgorithmExtensions
{
公共静态异步任务ComputeHashAsync(此HashAlg算法,IEnumerable文件,bool includePaths=true)
{
使用(var cs=newcryptostream(Stream.Null、alg、CryptoStreamMode.Write))
{
foreach(文件中的var文件)
{
如果(包括路径)
{
var pathBytes=Encoding.UTF8.GetBytes(file.FullName);
cs.Write(pathBytes,0,pathBytes.Length);
}
使用(var fs=file.OpenRead())
等待fs.CopyToAsync(cs);
}
cs.FlushFinalBlock();
}
返回alg.Hash;
}
}
对文件夹中的所有文件进行哈希处理的示例:

async Task<byte[]> HashFolder(DirectoryInfo folder, string searchPattern = "*", SearchOption searchOption = SearchOption.TopDirectoryOnly)
{
    using(var alg = MD5.Create())
        return await alg.ComputeHashAsync(folder.EnumerateFiles(searchPattern, searchOption));
}
异步任务HashFolder(DirectoryInfo文件夹,字符串searchPattern=“*”,SearchOption SearchOption=SearchOption.TopDirectoryOnly) { 使用(var alg=MD5.Create()) return wait alg.ComputeHashAsync(folder.EnumerateFiles(searchPattern,searchOption)); }
快速且脏的文件夹哈希,不会下到子订单或读取二进制数据。它基于文件名和子文件夹名

Public Function GetFolderHash(ByVal sFolder As String) As String
    Dim oFiles As List(Of String) = IO.Directory.GetFiles(sFolder).OrderBy(Function(x) x.Count).ToList()
    Dim oFolders As List(Of String) = IO.Directory.GetDirectories(sFolder).OrderBy(Function(x) x.Count).ToList()
    oFiles.AddRange(oFolders)

    If oFiles.Count = 0 Then
        Return ""
    End If

    Dim oDM5 As System.Security.Cryptography.MD5 = System.Security.Cryptography.MD5.Create()
    For i As Integer = 0 To oFiles.Count - 1
        Dim sFile As String = oFiles(i)
        Dim sRelativePath As String = sFile.Substring(sFolder.Length + 1)
        Dim oPathBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(sRelativePath.ToLower())

        If i = oFiles.Count - 1 Then
            oDM5.TransformFinalBlock(oPathBytes, 0, oPathBytes.Length)
        Else
            oDM5.TransformBlock(oPathBytes, 0, oPathBytes.Length, oPathBytes, 0)
        End If
    Next

    Return BitConverter.ToString(oDM5.Hash).Replace("-", "").ToLower()
End Function

谢谢你的回复。字符串可能非常大,所以我需要将其划分为块,只是考虑如何正确地进行。我记得C#hasher有一个函数向它们提供块,最后你可以要求得到最终的哈希,但不确定这些函数/类是什么。有了它们,你可以在内存中按你喜欢的方式对输入进行排序,然后循环文件并将数据块加载到几百KBs中,然后将其馈送到哈希器,这样你不需要太多内存,但仍然需要一些时间进行哈希运算,这是您无法摆脱的。这可能会导致内存相关问题。如果您将其部署到具有强制FIPS的本地安全策略的服务器上,请注意FIPS合规性compliance@SkeetJon这种技术对于任何加密算法都是一样的,所以你可以用SHA代替FIPS机器使用“*”而不是“**”
文件。ReadAllBytes
可以证明此方法非常占用内存。在您的方法中,如果文件系统以不同的顺序返回相同的文件,我们将得到不同的哈希值。这是唯一一个还考虑了所有元信息(如日期、访问权限、UID、guid等)的答案。如果使用此版本,您需要将
文件路径
截断为相对路径,以创建
路径字节
。这样做的关键是,您可以更改文件名,但仍然可以得到相同的哈希值-可能是您想要的,可能不是。此外,我建议您对文件名进行排序,并使用
path.GetRelativePath(folder,file.FullName)
所以散列是st