Script de PowerShell para calcular sumas de comprobación MD4 parciales

Script de PowerShell para calcular sumas de comprobación MD4 parciales

Necesito un script que lea un archivo de entrada y calcule sumas de comprobación MD4 para cada fragmento de 9728000 bytes, hasta el final del archivo. He hecho esto anteriormente extrayendo primero todos los fragmentos de 9728000 bytes como archivos individuales y luego calculando la suma de comprobación MD4 para cada uno con una herramienta de línea de comandos llamadafsum, pero eso no es conveniente, especialmente con archivos grandes.

Por lo que pude deducir, PowerShell puede calcular de forma nativa sumas de comprobación MD5, pero no MD4.

Hice pruebas con el siguiente script, adaptado del código obtenidoallá, y que todavía no entiendo del todo.

$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
}

Los resultados fueron los siguientes:

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
...

Pero 1) este no es el diseño que necesito, 2) necesito MD4 específicamente, y 3) otro problema es que el bucle no se detiene incluso cuando no hay más datos para leer, a pesar de la $offset -lt $lengthcondición (debo estar haciéndolo mal ).

Lo que necesito son cadenas MD4 normales de 32 bytes:

908CB75033311ADCB0FBCD0DCD869050 0
A1211C1B77C0EFFA98DB8F719AB30A93 9728000
D9719A4CB32F2D350CB39A0CB790424B 19456000
...

Entonces hoy encontréeste script MD4. Intenté usarlo adaptando el script anterior, perofalló miserablemente. Además, la función no se reconocía si copiaba todo el contenido del script (comenzando con function Get-MD4...) dentro de mi propio script, funciona solo si invoco el script a través de "punto-sourcing" (un concepto que descubrí en el camino mientras pasaba alrededor de 2 horas en esto, examinando varios libros PDF de más de 400 páginas en PowerShell que de otra manera apenas ayudaron). ¿Podría deberse a un problema de formato? (Si abro el script md4.ps1 en Notepad2, dice que los finales de línea son "LF", mientras que mi script tiene finales de línea "CR+LF". No es el problema principal, pero realmente me molestó. esta tarde, así que me gustaría saber qué estaba pasando.)

Elarchivo LÉAMEporque ese script contiene esto:

 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

No entiendo la línea que comienza $b =y no tengo idea de cómo podría encontrar algo relevante en esos libros en PDF o en una búsqueda en la Web. Así que una vez más estoy perdido.

¿Cuál sería la forma más eficiente de leer un archivo en un fragmento de tamaño definido a la vez, alimentarlo como entrada para la Get-MD4función, luego incrementar el valor de $offset, y así sucesivamente, hasta el final del archivo? ¿Debo usar -Stringo -bArray?

El objetivo, si eso es importante, es comprobar los archivos que se comparten en la red eDonkey pero con una suma de comprobación ED2K que no coincide. Por ejemplo, tengo un archivo MKV de 4 GB, al buscar con eMule encontré un archivo MKV con exactamente el mismo tamaño pero con una suma de verificación ED2K diferente, así que quiero saber qué partes específicas son diferentes (la suma de verificación ED2K es la suma de verificación MD4 del lista de cadenas MD4 para cada fragmento de 9728000 bytes, que se puede encontrar en el archivo de metadatos), luego puedo descargar específicamente esas partes para verificar si la versión corrupta de ese archivo es la que tengo o la que está compartida actualmente . Espero que quede claro. De lo contrario, no importa, centrémonos en el tema que nos ocupa, que es "Calcular sumas de comprobación MD4 parciales".

Respuesta1

El código anterior es muy ineficiente porque en cada iteración del bucle se crea un nuevo búfer enorme y una nueva secuencia. Elarroyoya maneja las compensaciones y todo por usted, por lo que el cuerpo del bucle es realmente muy simple:

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()

Esa es una gran mejora con respecto a su código, pero obviamente no es ella manera más eficienteporque elmd4.ps1El script anterior fue escrito para una versión muy antigua de PowerShell y es enormemente ineficiente. También maneja Unicode incorrectamente, por lo que su uso -Stringpuede devolver un resultado dañado. De todos modos, puedes probarlo guardando mi código actualizado arriba como un archivo *.ps1 como Get-ChunkMd4.ps1. Salida de muestra:

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

Dicho esto, nunca podrás tener elmayoríamanera eficiente a menos que escriba algún código paralelo altamente eficiente con aceleración de hardware y/o SIMD y lo compile en código nativo. Una biblioteca MD4 nativa puede ejecutarse miles o millones de veces más rápido que el script anterior. De hecho, una buena biblioteca de hash que utilice AVX-512 puede realizar hash en3-30 GB/so más, pero md4.ps1es tan malo que se necesitan 4 minutos solo para procesar un pequeño archivo de 8,2 MB en mi máquina (Ryzen 5 4600H), que es¡¡¡~29,5 KB/s!!!Tenga la seguridad de que ni siquiera podrá codificar el archivo de vídeo lo suficientemente rápido mientras lo descarga. Realmente deberías encontrar una biblioteca/herramienta de terceros y proporcionarles datos con el bucle anterior.


También tenga en cuenta que si usa mucho una función, debe agregarla al perfil de esta manera.

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

Ahora puede eliminarlo . .\md4.ps1en su secuencia de comandos porque la función se cargará cada vez que se ejecute PowerShell.

información relacionada