Hilfe bei der MD5 Hash Erstellung (Hash.au3)

  • Hallo,

    ich habe ein Problem mit der Funktion _MD5ForFile aus der Hash.au3 einen MD5 Hash für größere (>1GB) Dateien zu erstellen. Die Funktion bricht immer mit dem Error 3 ab, was laut Beschreibung "3 - MapViewOfFile function or call to it failed" bedeutet. Ich habe schon einige Tests durchgeführt und festgestellt das es mit der RAM Größe im System zusammenhängt. Die Funktion versucht die gesamte Datei in den RAM zu laden um den Hash zu erstellen und wenn im PC nicht genügend RAM vorhanden ist, kommt diese Fehlermeldung. In der MSDN habe ich dann auch entsprechende Hinweise dazu gefunden.

    http://msdn.microsoft.com/en-us/library/…1(v=vs.85).aspx

    "For files that are larger than the address space, you can only map a small portion of the file data at one time. When the first view is complete, you can unmap it and map a new view"
    Weiss einer von euch wie man diese Funktion so erweitert, dass sie die Dateien in kleineren Blöcken bearbeitet?
    Vielen Dank schon mal...

    [autoit]


    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _MD5ForFile
    ; Description ...: Calculates MD5 value for the specific file.
    ; Syntax.........: _MD5ForFile ($sFile)
    ; Parameters ....: $sFile - Full path to the file to process.
    ; Return values .: Success - Returns MD5 value in form of hex string
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - CreateFile function or call to it failed.
    ; |2 - CreateFileMapping function or call to it failed.
    ; |3 - MapViewOfFile function or call to it failed.
    ; |4 - MD5Init function or call to it failed.
    ; |5 - MD5Update function or call to it failed.
    ; |6 - MD5Final function or call to it failed.
    ; Author ........: trancexx
    ;
    ;==========================================================================================
    Func _MD5ForFile($sFile)

    [/autoit][autoit][/autoit][autoit]

    Local $a_hCall = DllCall("kernel32.dll", "hwnd", "CreateFileW", _
    "wstr", $sFile, _
    "dword", 0x80000000, _ ; GENERIC_READ
    "dword", 1, _ ; FILE_SHARE_READ
    "ptr", 0, _
    "dword", 3, _ ; OPEN_EXISTING
    "dword", 0, _ ; SECURITY_ANONYMOUS
    "ptr", 0)

    [/autoit][autoit][/autoit][autoit]

    If @error Or $a_hCall[0] = -1 Then
    Return SetError(1, 0, "")
    EndIf

    [/autoit][autoit][/autoit][autoit]

    Local $hFile = $a_hCall[0]

    [/autoit][autoit][/autoit][autoit]

    $a_hCall = DllCall("kernel32.dll", "ptr", "CreateFileMappingW", _
    "hwnd", $hFile, _
    "dword", 0, _ ; default security descriptor
    "dword", 2, _ ; PAGE_READONLY
    "dword", 0, _
    "dword", 0, _
    "ptr", 0)

    [/autoit][autoit][/autoit][autoit]

    If @error Or Not $a_hCall[0] Then
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFile)
    Return SetError(2, 0, "")
    EndIf

    [/autoit][autoit][/autoit][autoit]

    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFile)

    [/autoit][autoit][/autoit][autoit]

    Local $hFileMappingObject = $a_hCall[0]

    [/autoit][autoit][/autoit][autoit]

    $a_hCall = DllCall("kernel32.dll", "ptr", "MapViewOfFile", _
    "hwnd", $hFileMappingObject, _
    "dword", 4, _ ; FILE_MAP_READ
    "dword", 0, _
    "dword", 0, _
    "dword", 0)

    [/autoit][autoit][/autoit][autoit]

    If @error Or Not $a_hCall[0] Then
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
    Return SetError(3, 0, "")
    EndIf

    [/autoit][autoit][/autoit][autoit]

    Local $pFile = $a_hCall[0]
    Local $iBufferSize = FileGetSize($sFile)

    [/autoit][autoit][/autoit][autoit]

    Local $tMD5_CTX = DllStructCreate("dword i[2];" & _
    "dword buf[4];" & _
    "ubyte in[64];" & _
    "ubyte digest[16]")

    [/autoit][autoit][/autoit][autoit]

    DllCall("advapi32.dll", "none", "MD5Init", "ptr", DllStructGetPtr($tMD5_CTX))

    [/autoit][autoit][/autoit][autoit]

    If @error Then
    DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
    Return SetError(4, 0, "")
    EndIf

    [/autoit][autoit][/autoit][autoit]

    DllCall("advapi32.dll", "none", "MD5Update", _
    "ptr", DllStructGetPtr($tMD5_CTX), _
    "ptr", $pFile, _
    "dword", $iBufferSize)

    [/autoit][autoit][/autoit][autoit]

    If @error Then
    DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
    Return SetError(5, 0, "")
    EndIf

    [/autoit][autoit][/autoit][autoit]

    DllCall("advapi32.dll", "none", "MD5Final", "ptr", DllStructGetPtr($tMD5_CTX))

    [/autoit][autoit][/autoit][autoit]

    If @error Then
    DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)
    Return SetError(6, 0, "")
    EndIf

    [/autoit][autoit][/autoit][autoit]

    DllCall("kernel32.dll", "int", "UnmapViewOfFile", "ptr", $pFile)
    DllCall("kernel32.dll", "int", "CloseHandle", "hwnd", $hFileMappingObject)

    [/autoit][autoit][/autoit][autoit]

    Local $sMD5 = Hex(DllStructGetData($tMD5_CTX, "digest"))

    [/autoit][autoit][/autoit][autoit]

    Return SetError(0, 0, $sMD5)

    [/autoit][autoit][/autoit][autoit]

    EndFunc ;==>_MD5ForFile

    [/autoit]

    Einmal editiert, zuletzt von edmann (3. August 2011 um 17:26)

  • Bei MD5 geht es leider darum, die Daten als ganzes zu hashen.
    Du könntest deine Datei natürlich splitten, aber das Ergebnis hat dann nichts mehr mit MD5 zu tun.

  • Ich hoffe, dass ich mich vorhin geirrt habe.
    Ich hab grad mal 20min versucht meine Idee umzusetzen, aber dabei ist nicht viel herausgekommen.
    Meine Idee ansich würde schon funktionieren, aber die Umsetzung in AutoIt ist nicht so leicht wie ich dachte.
    Das habe ich bis jetzt erreicht: (wenn jemand das Skript fertig stellen kann, poste ich die Binary-Funktionen aus der UDF.)

    [autoit]

    #include-once
    #include <ChristophX86Binary.au3>

    [/autoit][autoit][/autoit][autoit]

    Func _MD5_HashFile($File)
    If Not FileExists($File) Then
    SetError(1)
    Return ''
    EndIf
    $FileLen = FileGetSize($File)*8
    $PaddingBits = '1'
    If Mod($FileLen+StringLen($PaddingBits)+64, 512) <> 0 Then
    Do
    $PaddingBits &= '0'
    Until Mod($FileLen+StringLen($PaddingBits)+64, 512) = 0
    EndIf
    ConsoleWrite('Message Length after Padding: ' & $FileLen+StringLen($PaddingBits) & @CRLF)
    $BinaryLen = _DecimalToBinary($FileLen, 50, False, False)
    If StringLen($BinaryLen) > 64 Then
    $BinaryLen = StringRight($BinaryLen, 64)
    ElseIf StringLen($BinaryLen) < 64 Then
    Do
    $BinaryLen = '0' & $BinaryLen
    Until StringLen($BinaryLen) = 64
    EndIf
    ConsoleWrite('Original File Length: ' & StringLen($BinaryLen) & @CRLF)7
    $MessageLen = $FileLen+StringLen($BinaryLen)+StringLen($PaddingBits)
    ConsoleWrite('Message Length after appending Original Length: ' & $MessageLen & @CRLF)
    Local $A = 0x67452301
    Local $B = 0xefcdab89
    Local $C = 0x98badcfe
    Local $D = 0x10325476
    #cs
    This step uses a 64-element table T[1 ... 64] constructed from the
    sine function. Let T[i] denote the i-th element of the table, which
    is equal to the integer part of 4294967296 times abs(sin(i)), where i
    is in radians.
    #ce
    For $i = 0 To ($MessageLen/32)-1 Step 1
    $X = StringSplit(_StringToBinary(FileRead($File, 2)), '', 2)
    $AA = $A
    $BB = $B
    $CC = $C
    $DD = $D
    #cs
    /* Round 1. */
    /* Let [abcd k s i] denote the operation
    a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
    #ce
    $A = $B + BitShift(($A + F($B, $C, $D) + $X[?] + $T[$i]), -$s)
    #cs
    /* Do the following 16 operations. */
    [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
    [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
    [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
    [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]
    #ce

    [/autoit][autoit][/autoit][autoit]

    #cs
    /* Round 2. */
    /* Let [abcd k s i] denote the operation
    a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
    /* Do the following 16 operations. */
    [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
    [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
    [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
    [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]
    #ce

    [/autoit][autoit][/autoit][autoit]

    #cs
    /* Round 3. */
    /* Let [abcd k s t] denote the operation
    a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
    /* Do the following 16 operations. */
    [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
    [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
    [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
    [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]
    #ce

    [/autoit][autoit][/autoit][autoit]

    #cs
    /* Round 4. */
    /* Let [abcd k s t] denote the operation
    a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
    /* Do the following 16 operations. */
    [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
    [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
    [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
    [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]
    #ce
    $A += $AA
    $B += $BB
    $C += $CC
    $D += $DD
    Next
    #cs
    The message digest produced as output is A, B, C, D. That is, we
    begin with the low-order byte of A, and end with the high-order byte
    of D.
    #ce
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func F($X, $Y, $Z)
    ; XY v not(X) Z
    If $X Then
    Return $Y
    Else
    Return $Z
    EndIf
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func G($X, $Y, $Z)
    ; XZ v Y not(Z)
    If $X Then
    If Not $Z Then
    Return $Y
    EndIf
    Return $Z
    EndIf
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func H($X, $Y, $Z)
    ; X xor Y xor Z
    Return Hex(BitXOR($X, $Y, $Z))
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    Func I($X, $Y, $Z)
    ; Y xor (X v not(Z))
    Return BitXOR($Y, $X, BitNOT($Z))
    EndFunc

    [/autoit]
  • Mal ne andere Frage. Warum ist es überhaupt nötig die gasamte Datei in den Speicher einzulesen? Kann man den Hash nicht direkt von der Platte erstellen? Ich weiss, es würde daduch bedeutend langsamer laufen, würde aber wenigstens funktionieren.

  • Versuchs mal mit

    Code
    _Crypt_HashFile()


    bei mir gehts damit auch für große dateien.

  • Versuchs mal mit

    [autoit]

    _Crypt_HashFile()

    [/autoit]

    bei mir gehts damit auch für große dateien.


    ja damit hatte ich bisher keine Probleme.

    @TE schau dir dazu das Beispiel in der Hilfe an, damit kannst du ja testen ob es funktioniert,

    mfg autoBert

  • Super. Funktioniert!!! Vielen Dank. Weiss garnicht warum ich da nicht selber darauf gekommen bin ?( Mich wundert nur warum es hier geht, denn die Funktion arbeitet sehr ähnlich der in der Hash.au3. Hier wird auch am Anfang das gesamte File mit

    [autoit]


    $bTempData = FileRead($hFile, 512 * 1024)

    [/autoit]


    eingelesen und dann mit

    [autoit]


    $hHashObject = _Crypt_HashData($bTempData, $iALG_ID, False, $hHashObject)

    [/autoit]


    der Hash gebildet. Im Taskmanager sieht man aber dass der Speicherverbrauch des Tasks nie über 6-7MB hinaus geht.
    Sehr seltsam... Aber wie auch immer, Hauptsache es funktioniert :thumbup:

  • Nein, es wird immer nur ein Teil der Datei eingelesen, dem Hash hinzugefügt und dann der nächste Teil genommen. Den Code von _MD5ForFile könnte man ebenfalls so anpassen, aber wozu wenn es schon eine Funktion gibt ;)

  • Na gut

    Spoiler anzeigen
    [autoit]

    #include<WinAPI.au3>
    #include<Crypt.au3>
    ; #FUNCTION# ;===============================================================================
    ;
    ; Name...........: _MD5ForFile
    ; Description ...: Calculates MD5 value for the specific file.
    ; Syntax.........: _MD5ForFile ($sFile)
    ; Parameters ....: $sFile - Full path to the file to process.
    ; Return values .: Success - Returns MD5 value in form of binary data
    ; - Sets @error to 0
    ; Failure - Returns empty string and sets @error:
    ; |1 - CreateFile function or call to it failed.
    ; |2 - MD5Init function or call to it failed.
    ; |4 - ReadFile function or call to it failed.
    ; |5 - MD5Update function or call to it failed.
    ; |6 - MD5Final function or call to it failed.
    ; Author ........: trancexx
    ;
    ;==========================================================================================
    Func _MD5ForFile($sFile)

    [/autoit] [autoit][/autoit] [autoit]

    Local $a_hCall = DllCall("kernel32.dll", "hwnd", "CreateFileW", _
    "wstr", $sFile, _
    "dword", 0x80000000, _ ; GENERIC_READ
    "dword", 1, _ ; FILE_SHARE_READ
    "ptr", 0, _
    "dword", 3, _ ; OPEN_EXISTING
    "dword", 0, _ ; SECURITY_ANONYMOUS
    "ptr", 0)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Or $a_hCall[0] = -1 Then
    Return SetError(1, 0, "")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $hFile = $a_hCall[0]

    [/autoit] [autoit][/autoit] [autoit]

    Local $tMD5_CTX = DllStructCreate("dword i[2];" & _
    "dword buf[4];" & _
    "ubyte in[64];" & _
    "ubyte digest[16]")

    [/autoit] [autoit][/autoit] [autoit]

    DllCall("advapi32.dll", "none", "MD5Init", "ptr", DllStructGetPtr($tMD5_CTX))

    [/autoit] [autoit][/autoit] [autoit]

    If @error Then
    _WinAPI_CloseHandle($hFile)
    Return SetError(2, 0, "")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Local $tBuffer = DllStructCreate("byte[524288]")
    Local $pBuffer = DllStructGetPtr($tBuffer), $iSize

    [/autoit] [autoit][/autoit] [autoit]

    Local $iReadErr = True
    While _WinAPI_ReadFile($hFile, $pBuffer, 524288, $iSize) And $iSize
    $iReadErr = False

    [/autoit] [autoit][/autoit] [autoit]

    DllCall("advapi32.dll", "none", "MD5Update", _
    "ptr", DllStructGetPtr($tMD5_CTX), _
    "ptr", $pBuffer, _
    "dword", $iSize)

    [/autoit] [autoit][/autoit] [autoit]

    If @error Then
    _WinAPI_CloseHandle($hFile)
    Return SetError(5, 0, "")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    WEnd
    If $iReadErr Then
    _WinAPI_CloseHandle($hFile)
    Return SetError(4, 0, "")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    DllCall("advapi32.dll", "none", "MD5Final", "ptr", DllStructGetPtr($tMD5_CTX))

    [/autoit] [autoit][/autoit] [autoit]

    If @error Then
    _WinAPI_CloseHandle($hFile)
    Return SetError(6, 0, "")
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    _WinAPI_CloseHandle($hFile)

    [/autoit] [autoit][/autoit] [autoit]

    Local $sMD5 = DllStructGetData($tMD5_CTX, "digest")

    [/autoit] [autoit][/autoit] [autoit]

    Return SetError(0, 0, $sMD5)

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_MD5ForFile

    [/autoit] [autoit][/autoit] [autoit]

    MsgBox(0, '', _MD5ForFile(@AutoItExe) & @CRLF & _Crypt_HashFile(@AutoItExe, $CALG_MD5))

    [/autoit]