用于计算部分 MD4 校验和的 PowerShell 脚本

用于计算部分 MD4 校验和的 PowerShell 脚本

我需要一个脚本来读取输入文件并计算每个 9728000 字节块的 MD4 校验和,直到文件结束。我之前曾这样做过,首先将所有 9728000 字节块提取为单个文件,然后使用名为的命令行工具计算每个文件的 MD4 校验和总和,但这并不方便,尤其是对于大文件而言。

据我所知,PowerShell 可以本机计算 MD5 校验和,但不能计算 MD4。

我使用以下脚本进行了测试,该脚本改编自获得的代码那里,但我还是不完全理解。

$input = Read-Host "File name"
$file = Get-Item -LiteralPath $input
$offset = 0
$length = $file.length
$name = $file.name
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create('MD5')
for ($offset -lt $length) {
    $buffer = [Byte[]]::new(9728000)
    $stream = [System.IO.FileStream]::new($file.FullName, 'Open', 'Read')
    $stream.Position = $offset
    $readSize = $stream.Read($buffer, 0, 9728000)
    $md5 = $hasher.ComputeHash($buffer, 0, $readSize)
    $stream.Dispose()
    echo "$md5 $offset" >> "$name MD5.txt"
    $offset = $offset + 9728000
}

结果如下:

78 224 90 67 158 49 86 127 118 179 251 89 133 103 144 25 0
190 40 170 149 51 93 153 191 212 194 162 165 38 124 57 96 9728000
160 20 197 150 189 246 209 156 212 84 154 21 200 7 148 228 19456000
...

但是 1) 这不是我需要的布局,2) 我特别需要 MD4,3) 另一个问题是,尽管有条件,但即使没有更多数据可读取,循环也不会停止$offset -lt $length(我一定是做错了)。

我需要的是常规的 32 字节 MD4 字符串:

908CB75033311ADCB0FBCD0DCD869050 0
A1211C1B77C0EFFA98DB8F719AB30A93 9728000
D9719A4CB32F2D350CB39A0CB790424B 19456000
...

然后今天我发现这个 MD4 脚本。我尝试通过修改上述脚本来使用它,但是失败了,misebarly。此外,如果我将脚本的全部内容(以 开头function Get-MD4...)复制到我自己的脚本中,该函数也无法被识别,只有通过“点源”调用脚本时它才有效(这是我在花了大约 2 个小时研究这个概念的过程中发现的一个概念,我查阅了几本 400 多页的 PowerShell PDF 书,但除此之外几乎没有帮助)。这可能是由于格式问题造成的吗?(如果我在 Notepad2 中打开 md4.ps1 脚本,它会显示行尾是“LF”,而我的脚本有“CR+LF”行尾。这不是主要问题,但它今天下午真的让我很恼火,所以我想知道发生了什么。)

自述文件因为该脚本包含以下内容:

 This is a MD4 algorithm function wrote in powershell.
 
 PS> Get-MD4 -String 'abc' -UpperCase
 A448017AAF21D8525FC10AE87AA6729D
 
 PS> $b = @('abc'.ToCharArray() | %{[int]$_})
 PS> Get-MD4 -bArray $b
 a448017aaf21d8525fc10ae87aa6729d

我不明白开头的那行$b =,也不知道如何在这些 PDF 书籍或网络搜索中找到相关内容。所以我再次不知所措。

一次读取一个大小定义的块的文件,将其作为函数的输入Get-MD4,然后增加 $offset 值,依此类推,直到文件末尾,最有效的方法是什么?我应该使用-String还是-bArray

如果这很重要的话,目标是检查在 eDonkey 网络上共享但 ED2K 校验和不匹配的文件。例如,我有一个 4GB 的 MKV 文件,使用 eMule 搜索时,我发现一个大小完全相同但 ED2K 校验和不同的 MKV 文件,因此我想知道哪些特定部分不同(ED2K 校验和是每个 9728000 字节块的 MD4 字符串列表的 MD4 校验和,可以在元数据文件中找到),然后我可以专门下载这些部分,以检查该文件的损坏版本是我拥有的还是当前共享的。希望这很清楚。否则,没关系,让我们专注于手头的主题“计算部分 MD4 校验和”。

答案1

上述代码效率极低,因为每次循环迭代都会创建一个新的大缓冲区和一个新的流。溪流已经为您处理了偏移量和所有内容,因此循环体实际上非常简单:

Param (
    [parameter(Mandatory)][string]$InputFile,
    [int]$ChunkSize = 9728000
)

. .\md4.ps1
# Or copy the md4.ps1 content here, or add to the $PROFILE

class Md4Info {
    [string]$Checksum
    [int]$Offset
}

$stream = [IO.FileStream]::new($InputFile, [IO.FileMode]::Open, [IO.FileAccess]::Read)
$buffer = [Byte[]]::new($ChunkSize)
while (($readSize = $stream.Read($buffer, 0, $ChunkSize)) -gt 0) {
    [Md4Info]@{
        Checksum = Get-MD4 -bArray $buffer[0..$readSize]
        Offset = $stream.Position
    }
}
$stream.Dispose()

这比你的代码有了很大的改进,但显然它不是最有效的方法因为MD4.PS1上面的脚本是为非常老的 PowerShell 版本编写的,效率极低。它还会错误地处理 Unicode,因此使用-String可能会返回损坏的输出。无论如何,您可以通过将我上面的更新代码保存为 *.ps1 文件(例如)来尝试Get-ChunkMd4.ps1。示例输出:

PS D:\test> .\Get-ChunkMd4.ps1 D:\test\file.txt

Checksum                         Offset
--------                         ------
11cf3ecf1a3a9d1b270c9e313901441d      0

PS D:\test> .\Get-ChunkMd4.ps1 D:\test\file.mp4 -ChunkSize 1MB

Checksum                          Offset
--------                          ------
8932ec620ef5df53f519e6271931bc0d       0
92a8f97be075655bfd1e8670368ff2a3 1048576
c6ec8e0d67b42cc3a9a1bc9d5c9fa8f0 2097152
1339bac99b94397b5848d1d86b0cc49e 3145728
fd643f329daeb73e07e24194fd1b0a31 4194304

话虽如此,你永远不可能拥有最多除非你使用硬件加速和/或 SIMD 编写一些高效的并行代码并编译为本机代码,否则这种方法是行不通的。本机 MD4 库的运行速度可能比上面的脚本快数千倍或数百万倍。事实上,使用 AVX-512 的良好哈希库可以达到3-30 GB/秒甚至更多,但md4.ps1它的表现非常糟糕,在我的机器(Ryzen 5 4600H)上,仅仅哈希一个 8.2 MB 的小文件就需要 4 分钟,这是~29.5 KB/s!!!放心吧,你下载视频文件时甚至无法快速哈希它们。你应该找到一个这样的第三方/工具,并使用上面的循环向它们提供数据


另请注意,如果您经常使用某个功能,那么您应该将其添加到配置文件中,如下所示

Add-Content -Path $profile -Value ". .\md4.ps1"

现在,您只需删除. .\md4.ps1脚本中的该函数即可,因为每次运行 PowerShell 时都会加载该函数

相关内容