Скрипт PowerShell для вычисления частичных контрольных сумм MD4

Скрипт PowerShell для вычисления частичных контрольных сумм MD4

Мне нужен скрипт, который будет читать входной файл и вычислять контрольные суммы MD4 для каждого 9728000-байтового фрагмента, до конца файла. Я уже делал это ранее, сначала извлекая все 9728000-байтовые фрагменты как отдельные файлы, а затем вычисляя контрольную сумму MD4 для каждого с помощью инструмента командной строки под названиемfsum, но это не удобно, особенно с большими файлами.

Насколько мне удалось выяснить, 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. Я попытался использовать его, адаптировав приведенный выше скрипт, нонеудачный неудачный. Кроме того, функция не распознавалась, если я копировал все содержимое скрипта (начиная с function Get-MD4...) в свой собственный скрипт, она работала только при вызове скрипта через «точечный источник» (концепция, которую я обнаружил по ходу дела, потратив около 2 часов на это, просматривая несколько 400+ страниц PDF-книг по PowerShell, которые в остальном едва ли помогали). Может ли это быть из-за проблемы с форматированием? (Если я открываю скрипт md4.ps1 в Notepad2, он сообщает, что строки заканчиваются на «LF», тогда как в моем скрипте строки заканчиваются на «CR+LF». Это не главная проблема, но она действительно вывела меня из себя сегодня днем, поэтому я хотел бы знать, что происходит.)

TheФайл READMEибо этот скрипт содержит это:

 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. Например, у меня есть файл MKV размером 4 ГБ, и, выполняя поиск с помощью eMule, я нашел файл MKV с точно таким же размером, но с другой контрольной суммой ED2K, поэтому я хочу узнать, какие именно части отличаются (контрольная сумма ED2K — это контрольная сумма MD4 списка строк MD4 для каждого фрагмента размером 9728000 байт, который можно найти в файле метаданных), затем я могу загрузить именно эти части, чтобы проверить, является ли поврежденная версия этого файла той, которая у меня есть, или той, которая в настоящее время находится в общем доступе. Надеюсь, это понятно. В противном случае, неважно, давайте сосредоточимся на теме, которая называется «Вычислить частичные контрольные суммы 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 ГБ/сили больше, но md4.ps1он настолько плох, что ему требуется 4 минуты только для хеширования маленького файла размером 8,2 МБ на моей машине (Ryzen 5 4600H), что~29,5 КБ/с!!!Будьте уверены, что вы даже не можете достаточно быстро хэшировать видеофайл, пока вы их загружаете. Вам действительно следует найти одну такую ​​стороннюю библиотеку/инструмент и скормить им данные с помощью цикла выше


Также обратите внимание, что если вы часто используете функцию, то вам следует добавить ее в профиль следующим образом:

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

Теперь вы можете просто удалить . .\md4.ps1из своего скрипта, поскольку функция будет загружаться каждый раз при запуске PowerShell.

Связанный контент