Hallo, ich habe im Inet Folgendes SH Script gefunden und würde dieses gerne in Autoit Realisieren.
Spoiler anzeigen
#!/bin/sh
# Challenge abholen
ChallengeXML=`wget -O - "http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml" 2>/dev/null| grep Challenge`
Challenge=`echo $ChallengeXML | awk '{match($0,/>[^<>]+</); print substr($0,RSTART+1,RLENGTH-2)}'`
Passwd="xxxxx"
# login aufbauen und hashen
CPSTR="$Challenge-$Passwd"
MD5=`echo -n $CPSTR | iconv -f ISO8859-1 -t UTF-16LE | md5sum -b | awk '{print substr($0,1,32)}'`
RESPONSE="$Challenge-$MD5"
POSTDATA="login:command/response=$RESPONSE&getpage=../html/de/menus/menu2.html"
# login senden und SID herausfischen
SID=`wget -O - --post-data="$POSTDATA" "http://fritz.box/cgi-bin/webcm" 2>/dev/null| grep "name=\"sid\"" | head -1 | awk '{match($0,/value="[^"]+"/); print substr($0,RSTART+7,RLENGTH-8)}'`
# refresh der daten auslösen
wget -O /dev/null "http://fritz.box//cgi-bin/webcm?sid=$SID&getpage=../html/de/menus/menu2.html&errorpage=../html/de/menus/menu2.html&var:pagename=foncalls&var:errorpagename=foncalls&var:menu=home&var:pagemaster=&var:activtype=pppoe&var:tabInetstat=0&var:weckernr=&logger:settings/filter=2"
# CSV runterladen
wget -O ../fb_anrufliste.csv "http://fritz.box/cgi-bin/webcm?sid=$SID&getpage=../html/de/FRITZ!Box_Anrufliste.csv" 2>/dev/null
#include <http.au3>
#include <MD5.au3>
$host = "fritz.box"
$Fritzpass = "XXXXXXXXX"
$Challenge=StringRegExp(_INetGetSource("http://fritz.box/cgi-bin/webcm?getpage=../html/login_sid.xml"),"<Challenge>(.*)</Challenge>",1)
$Challenge=$Challenge[0]
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $Challenge = ' & $Challenge & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$CPSTR=$Challenge & "-" & $Fritzpass
$MD5 = md5($CPSTR)
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $MD5 = ' & $MD5 & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$RESPONSE = $Challenge & "-" & $MD5
$POSTDATA="login:command/response=" & $RESPONSE & "&getpage=../html/de/menus/menu2.html"
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $POSTDATA = ' & $POSTDATA & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$httpsocet = _HTTPConnect($host)
$RC = _HTTPPost($host, "http://" & $host & "/cgi-bin/webcm", $httpsocet,$POSTDATA)
sleep(1000)
$RC = _HTTPRead($httpsocet,0)
$SID = StringRegExp($RC,'[nNaAmMeE]+="[sSiIdD]+"\s*[vVaAlLuUeE]+\s*=\s*"(.*)"\s+',1)
$SID = $SID[0]
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $SID = ' & $SID & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
$ErrorMessage = StringRegExp($RC,'errorMessage">(.*)<',1)
$ErrorMessage = $ErrorMessage[0]
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ErrorMessage = ' & $ErrorMessage & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $RC = ' & $RC & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
[/autoit]Nur leider bekomme ich immer nur Passwort Falsch ich denke irgendwas hab ich mit dem MD5 hash falsch gemacht.
Kann mir einer Helfen?
Edit: ich glaube ich habe es gefunden ich brauche eine Convertierung von ISO8859-1 UTF-16LE damit sollte es funktionieren wie kann ich den String in Autoit auf die Entsprechenden Formate Convertirern?
unter Linux get es mit "iconv -f ISO8859-1 -t UTF-16LE"
http.au3
Spoiler anzeigen
; ===================================================================
; HTTP UDF's
; v0.5
;
; By: Greg "Overload" Laabs
; Last Updated: 07-22-06
; Tested with AutoIt Version 3.1.1.131
; Extra requirements: Nothing!
;
; A set of functions that allow you to download webpages and submit
; POST requests.
;
; Main functions:
; _HTTPConnect - Connects to a webserver
; _HTTPGet - Submits a GET request to a webserver
; _HTTPPost - Submits a POST request to a webserver
; _HTTPRead - Reads the response from a webserver
; ===================================================================
TCPStartup()
[/autoit] [autoit][/autoit] [autoit]Global $_HTTPUserAgent = "AutoItScript/"&@AutoItVersion
Global $_HTTPLastSocket = -1
Global $_HTTPRecvTimeout = 30000
; ===================================================================
; _HTTPSetUserAgent($Program, $Version)
;
; Sets the User-Agent that will be sent with all future _HTTP
; functions. If this is never called, the user agent is set to
; AutoItScript/[YourAutoItVersion]
; Parameters:
;$Program - IN - The name of the program
;$Version - IN - The version number of the program
; Returns:
;None
; ===================================================================
Func _HTTPSetUserAgent($Program, $Version)
$_HTTPUserAgent = $Program&"/"&$Version
EndFunc
; ===================================================================
; _HTTPConnect($host, [$port])
;
; Opens a connection to $host on the port you supply (or 80 if you don't supply a port. Returns the socket of the connection.
; Parameters:
;$host - IN - The hostname you want to connect to. This should be in the format "www.google.com" or "localhost"
;$port - OPTIONAL IN - The port to connect on. 80 is default.
; Returns:
;The socket of the connection.
; Remarks:
; Possible @errors:
; 1 - Unable to open socket - @extended is set to Windows API WSAGetLasterror return
; ===================================================================
Func _HTTPConnect($host, $port = 80)
Dim $ip = TCPNameToIP ( $host )
Dim $socket = TCPConnect ( $ip, 80 )
If ($socket == -1) Then
SetError(1, @error)
Return -1
EndIf
$_HTTPLastSocket = $socket
SetError(0)
Return $socket
EndFunc
; Possible @errors:
; 1 - No socket
Func _HTTPClose($socket = -1)
If $socket == -1 Then
If $_HTTPLastSocket == -1 Then
SetError(1)
Return 0
EndIf
$socket = $_HTTPLastSocket
EndIf
TCPCloseSocket($socket)
SetError(0)
Return 1
EndFunc
; ===================================================================
; _HTTPGet($host, $page, [$socket])
;
; Executes a GET request on an open socket.
; Parameters:
;$host - IN - The hostname you want to get the page from. This should be in the format "www.google.com" or "localhost"
;$page - IN - The the file you want to get. This should always start with a slash. Examples: "/somepage.php" or "/somedirectory/somefile.zip"
;$socket - OPTIONAL IN - The socket opened by _HTTPConnect. If this is not supplied, the last socket opened with _HTTPConnect will be used.
; Returns:
;The number of bytes sent in the request.
; Remarks:
; Possible @errors:
; 1 - No socket supplied and no current socket exists
; 2 - Error sending to socket. Check @extended for Windows API WSAGetError return
; ===================================================================
Func _HTTPGet($host, $page, $socket = -1)
Dim $command
If $socket == -1 Then
If $_HTTPLastSocket == -1 Then
SetError(1)
Return
EndIf
$socket = $_HTTPLastSocket
EndIf
$command = "GET "&$page&" HTTP/1.1"&@CRLF
$command &= "Host: " &$host&@CRLF
$command &= "User-Agent: "&$_HTTPUserAgent&@CRLF
$command &= "Connection: close"&@CRLF
$command &= ""&@CRLF
Dim $bytessent = TCPSend($socket, $command)
[/autoit] [autoit][/autoit] [autoit]If $bytessent == 0 Then
SetExtended(@error)
SetError(2)
return 0
EndIf
SetError(0)
Return $bytessent
EndFunc
; ===================================================================
; _HTTPPost($host, $page, [$socket])
;
; Executes a POST request on an open socket.
; Parameters:
;$host - IN - The hostname you want to get the page from. This should be in the format "www.google.com" or "localhost"
;$page - IN - The the file you want to get. This should always start with a slash. Examples: "/" or "/somedirectory/submitform.php"
;$socket - OPTIONAL IN - The socket opened by _HTTPConnect. If this is not supplied, the last socket opened with _HTTPConnect will be used.
;$data - OPTIONAL IN - The data to send in the post request. This should first be run through _HTTPEncodeString()
; Returns:
;The number of bytes sent in the request.
; Remarks:
; Possible @errors:
; 1 - No socket supplied and no current socket exists
; 2 - Error sending to socket. Check @extended for Windows API WSAGetError return
; ===================================================================
Func _HTTPPost($host, $page, $socket = -1, $data = "")
Dim $command
If $socket == -1 Then
If $_HTTPLastSocket == -1 Then
SetError(1)
Return
EndIf
$socket = $_HTTPLastSocket
EndIf
Dim $datasize = StringLen($data)
[/autoit] [autoit][/autoit] [autoit]$command = "POST "&$page&" HTTP/1.1"&@CRLF
$command &= "Host: " &$host&@CRLF
$command &= "User-Agent: "&$_HTTPUserAgent&@CRLF
$command &= "Connection: close"&@CRLF
$command &= "Content-Type: application/x-www-form-urlencoded"&@CRLF
$command &= "Content-Length: "&$datasize&@CRLF
$command &= ""&@CRLF
$command &= $data&@CRLF
Dim $bytessent = TCPSend($socket, $command)
[/autoit] [autoit][/autoit] [autoit]If $bytessent == 0 Then
SetExtended(@error)
SetError(2)
return 0
EndIf
SetError(0)
Return $bytessent
EndFunc
; ===================================================================
; _HTTPRead([$socket], [$flag])
;
; Retrieves data from an open socket. This should only be called after _HTTPGet or _HTTPPost is called.
; Parameters:
;$socket - OPTIONAL IN - The socket you want to receive data from. If this is not supplied, the last socket opened with _HTTPConnect will be used.
;$flag - OPTIONAL IN - Determines how the data will be returned. See Remarks.
; Returns:
;See "Flags" in remarks, below.
; Remarks:
; Possible @errors:
; 1 - No socket
; 3 - Timeout reached before any data came through the socket
; 4 - Some data came through, but not all of it. Return value is the number of bytes received.
; 5 - Unable to parse HTTP Response from server. Return value is the HTTP Response line
; 6 - Unexpected header data returned. Return value is the line that caused the error
; 7 - Invalid flag
; 8 - Unable to parse chunk size. Return value is the line that caused the error
; Flags:
; 0 - Return value is the body of the page (default)
; 1 - Return value is an array:
; [0] = HTTP Return Code
; [1] = HTTP Return Reason (human readable return code like "OK" or "Forbidden"
; [2] = HTTP Version
; [3] = Two dimensional array with the headers. Each item has:
; [0] = Header name
; [1] = Header value
; [4] = The body of the page
; ===================================================================
Func _HTTPRead($socket = -1, $flag = 0)
If $socket == -1 Then
If $_HTTPLastSocket == -1 Then
SetError(1)
Return
EndIf
$socket = $_HTTPLastSocket
EndIf
Dim $timer = TimerInit()
Dim $performancetimer = TimerInit()
Dim $downloadtime = 0
Dim $headers[1][2] ; An Array of the headers found
Dim $numheaders = 0 ; The number of headers found
Dim $body = "" ; The body of the message
Dim $HTTPVersion ; The HTTP version of the server (almost always 1.1)
Dim $HTTPResponseCode ; The HTTP response code like 200, or 404
Dim $HTTPResponseReason ; The human-readable response reason, like "OK" or "Not Found"
Dim $bytesreceived = 0 ; The total number of bytes received
Dim $data = "" ; The entire raw message gets put in here.
Dim $chunked = 0 ; Set to 1 if we get the "Transfer-Encoding: chunked" header.
Dim $chunksize = 0 ; The size of the current chunk we are processing.
Dim $chunkprocessed = 0 ; The amount of data we have processed on the current chunk.
Dim $contentlength ; The size of the body, if NOT using chunked transfer mode.
Dim $part = 0 ; Refers to what part of the data we're currently parsing:
; 0 - Nothing parsed, so HTTP response should come next
; 1 - Currently parsing headers
; 2 - Currently waiting for the next chunk size - this is skipped if the transfer-encoding is not chunked
; 3 - Currently waiting for or parsing body data
; 4 - Currently parsing footers
;While 1
Sleep(10)
Dim $recv = TCPRecv($socket,16)
If @error <> 0 Then
;ConsoleWrite("Server closed connection")
;@error appears to be -1 after the server closes the connection. A good way to tell that we're finished, because we always send
;the "Connection: close" header to the server.
; !!! This is no longer used because we can now tell that we're done by checking the content-length header or properly handling
; chunked data.
EndIf
While $recv <> ""
;If $recv <> "" Then
$bytesreceived = $bytesreceived + StringLen($recv)
$timer = TimerInit()
$data &= $recv
;ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $data = ' & $data & @crlf & '>Error code: ' & @error & @crlf) ;### Debug Console
;ConsoleWrite("Bytes downloaded: "&$bytesreceived&@CRLF)
;EndIf
$recv = TCPRecv($socket,2048)
WEnd
Dim $split = StringSplit($data,@CRLF,1)
$data = ""
Dim $i
For $i=1 To $split[0]
If $i=$split[0] Then
If $part < 2 OR $chunked = 1 Then
; This is tricky. The last line we've received might be truncated, so we only want to process it under special cases.
; Non chunked data doesn't always send a CRLF at the end so there's no way to tell if this is truly the last line without parsing it.
; However, we don't want to parse it if it's only a partial header or something.
; The solution: We will only process this last line if we're at the body section and the transfer-encoding is NOT chunked.
$data = $split[$i]
ExitLoop
EndIf
EndIf
Dim $newpart = $part
Switch $part
Case 0 ; Nothing parsed, so HTTP response should come next
If $split[$i] <> "" Then
Dim $regex = StringRegExp($split[$i],"^HTTP/([0-9.]+) ([0-9]+) ([a-zA-Z0-9 ]+)$",3)
If @error <> 0 Then
SetError(5)
Return $split[$i]
Else
$HTTPVersion = $regex[0]
$HTTPResponseCode = $regex[1]
$HTTPResponseReason = $regex[2]
If $HTTPResponseCode <> 100 Then
$newpart = 1
EndIf
EndIf
EndIf
Case 1, 4 ; Currently parsing headers or footers
;If the line is blank, then we're done with headers and the body is next
If $split[$i] == "" Then
If $part = 1 Then
If $chunked Then
$newpart = 2
Else
$newpart = 3
EndIf
ElseIf $part = 4 Then
; If $part is 4 then we're processing footers, so we're all done now.
ExitLoop 2
EndIf
Else ;The line wasn't blank
;Check to see if the line begins with whitespace. If it does, it's actually
;a continuation of the previous header
Dim $regex = StringRegExp($split[$i], "^[ \t]+([^ \t].*)$", 3)
If @error <> 1 Then
If $numheaders == 0 Then
SetError(6)
Return $split[$i]
EndIf
$headers[$numheaders-1][1] &= $regex[0]
Else;The line didn't start with a space
Dim $regex = StringRegExp($split[$i],"^([^ :]+):[ \t]*(.*)$",3)
If @error <> 1 Then
;This is a new header, so add it to the array
$numheaders = $numheaders + 1
ReDim $headers[$numheaders][2]
$headers[$numheaders-1][0] = $regex[0]
$headers[$numheaders-1][1] = $regex[1]
; There are a couple headers we need to know about. We'll process them here.
If $regex[0] = "Transfer-Encoding" AND $regex[1] = "chunked" Then
$chunked = 1
ElseIf $regex[0] = "Content-Length" Then
$contentlength = Int($regex[1])
EndIf
Else
SetError(6)
Return $split[$i]
EndIf
EndIf
EndIf
Case 2 ; Awaiting chunk size
$regex = StringRegExp($split[$i],"^([0-9a-f]+);?.*$",3)
If @error <> 0 Then
SetError(8)
Return $split[$i]
EndIf
$chunksize = $regex[0]
$chunksize = Dec($chunksize)
$chunkprocessed = 0
If $chunksize == 0 Then
$newpart = 4
Else
$newpart = 3
EndIf
Case 3 ; Awaiting body data
$body &= $split[$i]
$chunkprocessed = $chunkprocessed + StringLen($split[$i])
[/autoit] [autoit][/autoit] [autoit]If $chunked Then
If $chunkprocessed >= $chunksize Then
$newpart = 2
Else
$body &= @CRLF
$chunkprocessed = $chunkprocessed + 2; We add 2 for the CRLF we stipped off.
EndIf
Else
If not $chunkprocessed >= $contentlength Then
If $i < $split[0] Then
; Only add a CRLF if this is not the last line received.
$body &= @CRLF
$chunkprocessed = $chunkprocessed + 2; We add 2 for the CRLF we stipped off.
EndIf
EndIf
EndIf
Case Else
; This should never happen
EndSwitch
$part = $newpart
Next
If $bytesreceived == 0 AND TimerDiff($timer) > $_HTTPRecvTimeout Then
SetError(3)
Return 0
ElseIf $bytesreceived > 0 AND TimerDiff($timer) > $_HTTPRecvTimeout Then
ConsoleWrite($body)
SetError(4)
Return $bytesreceived
EndIf
;WEnd
$downloadtime = TimerDiff($performancetimer)
;ConsoleWrite("Performance: Download time: "&$downloadtime&@CRLF)
Switch $flag
Case 0
SetError(0)
Return $body
Case 1
Dim $return[5]
$return[0] = $HTTPResponseCode
$return[1] = $HTTPResponseReason
$return[2] = $HTTPVersion
$return[3] = $headers
$return[4] = $body
SetError(0)
Return $return
Case Else
SetError(7)
Return 0
EndSwitch
EndFunc
; ===================================================================
; _HTTPEncodeString($string)
;
; Encodes a string so it can safely be transmitted via HTTP
; Parameters:
;$string - IN - The string to encode
; Returns:
;A valid encoded string that can be used as GET or POST variables.
; ===================================================================
Func _HTTPEncodeString($string)
Local Const $aURIValidChars[256] = _
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, _
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, _
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, _
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Local $sEncoded = ""
For $i = 1 To StringLen($string)
Local $c = StringMid($string, $i, 1)
If $c = " " Then $c = "+"
If Number($aURIValidChars[Asc($c) ]) Then
$sEncoded &= $c
Else
$sEncoded &= StringFormat("%%X", Asc($c))
EndIf
Next
Return $sEncoded
EndFunc ;==>_WebComposeURL
MD5.au3
Spoiler anzeigen
; Converted to AutoIt script by SvenP
;*******************************************************************************
; MODULE: CMD5
; FILENAME: C:\My Code\vb\md5\CMD5.cls
; AUTHOR: Phil Fresle
; CREATED: 16-Feb-2001
; COPYRIGHT:Copyright 2001 Frez Systems Limited. All Rights Reserved.
;
; DESCRIPTION:
; Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm,
; as set out in the memo RFC1321.
;
; This class is used to generate an MD5 ;digest; or ;signature; of a string. The
; MD5 algorithm is one of the industry standard methods for generating digital
; signatures. It is generically known as a digest, digital signature, one-way
; encryption, hash or checksum algorithm. A common use for MD5 is for password
; encryption as it is one-way in nature, that does not mean that your passwords
; are not free from a dictionary attack. If you are using the
; routine for passwords, you can make it a little more secure by concatenating
; some known random characters to the password before you generate the signature
; and on Funcsequent tests, so even if a hacker knows you are using MD5 for
; your passwords, the random characters will make it harder to dictionary attack.
;
; *** CAUTION ***
; See the comment attached to the MD5 method below regarding use on systems
; with different character sets.
;
; This is 'free' software with the following restrictions:
;
; You may not redistribute this code as a 'sample'or 'demo'. However, you are free
; to use the source code in your own code, but you may not claim that you created
; the sample code. It is expressly forbidden to sell or profit from this source code
; other than by the knowledge gained or the enhanced value added by your own code.
;
; Use of this software is also done so at your own risk. The code is supplied as
; is without warranty or guarantee of any kind.
;
; Should you wish to commission some derivative work based on this code provided
; here, or any consultancy work, please do not hesitate to contact us.
;
; Web Site: http://www.frez.co.uk
; E-mail:sales@frez.co.uk
;
; MODIFICATION HISTORY:
; 1.0 16-Feb-2001
; Phil Fresle
; Initial Version
;*******************************************************************************
Const $BITS_TO_A_BYTE = 8
Const $BYTES_TO_A_WORD = 4
Const $BITS_TO_A_WORD = $BYTES_TO_A_WORD * $BITS_TO_A_BYTE
Dim $m_lOnBits[31]
Dim $m_l2Power[31]
;*******************************************************************************
; Class_Initialize (Func)
;
; DESCRIPTION:
; We will usually get quicker results by preparing arrays of bit patterns and
; powers of 2 ahead of time instead of calculating them every time, unless of
; course the methods are only ever getting called once per instantiation of the
; class.
;*******************************************************************************
Func Class_Initialize()
; Could have done this with a loop calculating each value, but simply
; assigning the values is quicker - BITS SET FROM RIGHT
$m_lOnBits[0] = 1 ; 00000000000000000000000000000001
$m_lOnBits[1] = 3 ; 00000000000000000000000000000011
$m_lOnBits[2] = 7 ; 00000000000000000000000000000111
$m_lOnBits[3] = 15 ; 00000000000000000000000000001111
$m_lOnBits[4] = 31 ; 00000000000000000000000000011111
$m_lOnBits[5] = 63 ; 00000000000000000000000000111111
$m_lOnBits[6] = 127 ; 00000000000000000000000001111111
$m_lOnBits[7] = 255 ; 00000000000000000000000011111111
$m_lOnBits[8] = 511 ; 00000000000000000000000111111111
$m_lOnBits[9] = 1023 ; 00000000000000000000001111111111
$m_lOnBits[10] = 2047 ; 00000000000000000000011111111111
$m_lOnBits[11] = 4095 ; 00000000000000000000111111111111
$m_lOnBits[12] = 8191 ; 00000000000000000001111111111111
$m_lOnBits[13] = 16383 ; 00000000000000000011111111111111
$m_lOnBits[14] = 32767 ; 00000000000000000111111111111111
$m_lOnBits[15] = 65535 ; 00000000000000001111111111111111
$m_lOnBits[16] = 131071 ; 00000000000000011111111111111111
$m_lOnBits[17] = 262143 ; 00000000000000111111111111111111
$m_lOnBits[18] = 524287 ; 00000000000001111111111111111111
$m_lOnBits[19] = 1048575 ; 00000000000011111111111111111111
$m_lOnBits[20] = 2097151 ; 00000000000111111111111111111111
$m_lOnBits[21] = 4194303 ; 00000000001111111111111111111111
$m_lOnBits[22] = 8388607 ; 00000000011111111111111111111111
$m_lOnBits[23] = 16777215; 00000000111111111111111111111111
$m_lOnBits[24] = 33554431; 00000001111111111111111111111111
$m_lOnBits[25] = 67108863; 00000011111111111111111111111111
$m_lOnBits[26] = 134217727 ; 00000111111111111111111111111111
$m_lOnBits[27] = 268435455 ; 00001111111111111111111111111111
$m_lOnBits[28] = 536870911 ; 00011111111111111111111111111111
$m_lOnBits[29] = 1073741823 ; 00111111111111111111111111111111
$m_lOnBits[30] = 2147483647 ; 01111111111111111111111111111111
; Could have done this with a loop calculating each value, but simply
; assigning the values is quicker - POWERS OF 2
$m_l2Power[0] = 1 ; 00000000000000000000000000000001
$m_l2Power[1] = 2 ; 00000000000000000000000000000010
$m_l2Power[2] = 4 ; 00000000000000000000000000000100
$m_l2Power[3] = 8 ; 00000000000000000000000000001000
$m_l2Power[4] = 16 ; 00000000000000000000000000010000
$m_l2Power[5] = 32 ; 00000000000000000000000000100000
$m_l2Power[6] = 64 ; 00000000000000000000000001000000
$m_l2Power[7] = 128 ; 00000000000000000000000010000000
$m_l2Power[8] = 256 ; 00000000000000000000000100000000
$m_l2Power[9] = 512 ; 00000000000000000000001000000000
$m_l2Power[10] = 1024 ; 00000000000000000000010000000000
$m_l2Power[11] = 2048 ; 00000000000000000000100000000000
$m_l2Power[12] = 4096 ; 00000000000000000001000000000000
$m_l2Power[13] = 8192 ; 00000000000000000010000000000000
$m_l2Power[14] = 16384 ; 00000000000000000100000000000000
$m_l2Power[15] = 32768 ; 00000000000000001000000000000000
$m_l2Power[16] = 65536 ; 00000000000000010000000000000000
$m_l2Power[17] = 131072 ; 00000000000000100000000000000000
$m_l2Power[18] = 262144 ; 00000000000001000000000000000000
$m_l2Power[19] = 524288 ; 00000000000010000000000000000000
$m_l2Power[20] = 1048576 ; 00000000000100000000000000000000
$m_l2Power[21] = 2097152 ; 00000000001000000000000000000000
$m_l2Power[22] = 4194304 ; 00000000010000000000000000000000
$m_l2Power[23] = 8388608 ; 00000000100000000000000000000000
$m_l2Power[24] = 16777216; 00000001000000000000000000000000
$m_l2Power[25] = 33554432; 00000010000000000000000000000000
$m_l2Power[26] = 67108864; 00000100000000000000000000000000
$m_l2Power[27] = 134217728 ; 00001000000000000000000000000000
$m_l2Power[28] = 268435456 ; 00010000000000000000000000000000
$m_l2Power[29] = 536870912 ; 00100000000000000000000000000000
$m_l2Power[30] = 1073741824 ; 01000000000000000000000000000000
EndFunc
;*******************************************************************************
; LShift (FUNCTION)
;
; PARAMETERS:
; (In) - $lValue - Long- The value to be shifted
; (In) - $iShiftBits - Integer - The number of bits to shift the value by
;
; RETURN VALUE:
; Long - The shifted long integer
;
; DESCRIPTION:
; A left shift takes all the set binary bits and moves them left, in-filling
; with zeros in the vacated bits on the right. This function is equivalent to
; the << operator in Java and C++
;*******************************************************************************
Func LShift($lValue, $iShiftBits)
; NOTE: If you can guarantee that the Shift parameter will be in the
; range 1 to 30 you can safely strip of this first nested if structure for
; speed.
;
; A shift of zero is no shift at all.
If $iShiftBits = 0 Then
Return $lValue
; A shift of 31 will result in the right most bit becoming the left most
; bit and all other bits being cleared
ElseIf $iShiftBits = 31 Then
If BitAND($lValue, 1) Then
Return 0x80000000
Else
Return 0
Endif
; A shift of less than zero or more than 31 is undefined
ElseIf $iShiftBits < 0 Or $iShiftBits > 31 Then
SetError(6)
Endif
; If the left most bit that remains will end up in the negative bit
; position (0x80000000) we would end up with an overflow if we took the
; standard route. We need to strip the left most bit and add it back
; afterwards.
If BitAND($lValue, $m_l2Power[31 - $iShiftBits]) Then
; (Value And OnBits(31 - (Shift + 1))) chops off the left most bits that
; we are shifting into, but also the left most bit we still want as this
; is going to end up in the negative bit marker position (0x80000000).
; After the multiplication/shift we Or the result with 0x80000000 to
; turn the negative bit on.
Return BitOR((BitAND($lValue, $m_lOnBits[31 - ($iShiftBits + 1)]) * _
$m_l2Power[$iShiftBits]) , 0x80000000)
Else
[/autoit] [autoit][/autoit] [autoit]; (Value And OnBits(31-Shift)) chops off the left most bits that we are
; shifting into so we do not get an overflow error when we do the
; multiplication/shift
Return (BitAND($lValue, $m_lOnBits[31 - $iShiftBits]) * _
$m_l2Power[$iShiftBits])
Endif
EndFunc
;*******************************************************************************
; RShift (FUNCTION)
;
; PARAMETERS:
; (In) - $lValue - Long- The value to be shifted
; (In) - $iShiftBits - Integer - The number of bits to shift the value by
;
; RETURN VALUE:
; Long - The shifted long integer
;
; DESCRIPTION:
; The right shift of an unsigned long integer involves shifting all the set bits
; to the right and in-filling on the left with zeros. This function is
; equivalent to the >>> operator in Java or the >> operator in C++ when used on
; an unsigned long.
;*******************************************************************************
Func RShift($lValue, $iShiftBits)
Local $RShift
[/autoit] [autoit][/autoit] [autoit]; NOTE: If you can guarantee that the Shift parameter will be in the
; range 1 to 30 you can safely strip of this first nested if structure for
; speed.
;
; A shift of zero is no shift at all
If $iShiftBits = 0 Then
Return $lValue
; A shift of 31 will clear all bits and move the left most bit to the right
; most bit position
ElseIf $iShiftBits = 31 Then
If BitAND($lValue, 0x80000000) Then
Return 1
Else
Return 0
Endif
; A shift of less than zero or more than 31 is undefined
ElseIf $iShiftBits < 0 Or $iShiftBits > 31 Then
SetError(6)
Endif
; We do not care about the top most bit or the final bit, the top most bit
; will be taken into account in the next stage, the final bit (whether it
; is an odd number or not) is being shifted into, so we do not give a jot
; about it
$RShift = int(BitAND($lValue, 0x7FFFFFFE) / $m_l2Power[$iShiftBits])
; If the top most bit (0x80000000) was set we need to do things differently
; as in a normal VB signed long integer the top most bit is used to indicate
; the sign of the number, when it is set it is a negative number, so just
; deviding by a factor of 2 as above would not work.
; NOTE: (lValue And 0x80000000) is equivalent to (lValue < 0], you could
; get a very marginal speed improvement by changing the test to (lValue < 0)
If BitAND($lValue, 0x80000000) Then
; We take the value computed so far, and then add the left most negative
; bit after it has been shifted to the right the appropriate number of
; places
$RShift = int(BitOR($RShift, (0x40000000 / $m_l2Power[$iShiftBits - 1])))
Endif
Return $RShift
[/autoit] [autoit][/autoit] [autoit]EndFunc
[/autoit] [autoit][/autoit] [autoit];*******************************************************************************
; RShiftSigned (FUNCTION)
;
; PARAMETERS:
; (In) - $lValue - Long-
; (In) - $iShiftBits - Integer -
;
; RETURN VALUE:
; Long -
;
; DESCRIPTION:
; The right shift of a signed long integer involves shifting all the set bits to
; the right and in-filling on the left with the sign bit (0 if positive, 1 if
; negative. This function is equivalent to the >> operator in Java or the >>
; operator in C++ when used on a signed long integer. Not used in this class,
; but included for completeness.
;*******************************************************************************
Func RShiftSigned($lValue , $iShiftBits)
; NOTE: If you can guarantee that the Shift parameter will be in the
; range 1 to 30 you can safely strip of this first nested if structure for
; speed.
;
; A shift of zero is no shift at all
If $iShiftBits = 0 Then
Return $lValue
; A shift of 31 will clear all bits if the left most bit was zero, and will
; set all bits if the left most bit was 1 (a negative indicator)
ElseIf $iShiftBits = 31 Then
; NOTE: (lValue And 0x80000000) is equivalent to (lValue < 0), you
; could get a very marginal speed improvement by changing the test to
; (lValue < 0)
If BitAND($lValue, 0x80000000) Then
Return -1
Else
Return 0
Endif
; A shift of less than zero or more than 31 is undefined
ElseIf $iShiftBits < 0 Or $iShiftBits > 31 Then
SetError(6)
Endif
; We get the same result by dividing by the appropriate power of 2 and
; rounding in the negative direction
Return Int($lValue / $m_l2Power[$iShiftBits])
EndFunc
;*******************************************************************************
; RotateLeft (FUNCTION)
;
; PARAMETERS:
; (In) - $lValue - Long- Value to act on
; (In) - $iShiftBits - Integer - Bits to move by
;
; RETURN VALUE:
; Long - Result
;
; DESCRIPTION:
; Rotates the bits in a long integer to the left, those bits falling off the
; left edge are put back on the right edge
;*******************************************************************************
Func RotateLeft($lValue , $iShiftBits)
Return BitOR(LShift($lValue, $iShiftBits), RShift($lValue, (32 - $iShiftBits)))
EndFunc
;*******************************************************************************
; AddUnsigned (FUNCTION)
;
; PARAMETERS:
; (In) - $lX - Long - First value
; (In) - $lY - Long - Second value
;
; RETURN VALUE:
; Long - Result
;
; DESCRIPTION:
; Adds two potentially large unsigned numbers without overflowing
;*******************************************************************************
Func AddUnsigned($lX , $lY )
$lX8 = BitAND($lX, 0x80000000)
$lY8 = BitAND($lY, 0x80000000)
$lX4 = BitAND($lX, 0x40000000)
$lY4 = BitAND($lY, 0x40000000)
$lResult = BitAND($lX, 0x3FFFFFFF) + BitAND($lY, 0x3FFFFFFF)
If BitAND($lX4, $lY4) Then
$lResult = BitXOR($lResult, 0x80000000, $lX8, $lY8)
ElseIf BitOR($lX4 , $lY4) Then
If BitAND($lResult, 0x40000000) Then
$lResult = BitXOR($lResult, 0xC0000000, $lX8, $lY8)
Else
$lResult = BitXOR($lResult, 0x40000000, $lX8, $lY8)
Endif
Else
$lResult = BitXOR($lResult, $lX8, $lY8)
Endif
Return $lResult
EndFunc
;*******************************************************************************
; F (FUNCTION)
;
; DESCRIPTION:
; MD5's F function
;*******************************************************************************
Func F($x , $y , $z )
Return BitOR(BitAND($x, $y) , BitAND((BitNOT($x)), $z))
EndFunc
;*******************************************************************************
; G (FUNCTION)
;
; DESCRIPTION:
; MD5's G function
;*******************************************************************************
Func G($x , $y , $z )
Return BitOR(BitAND($x, $z) , BitAND($y , (BitNOT($z))))
EndFunc
;*******************************************************************************
; H (FUNCTION)
;
; DESCRIPTION:
; MD5's H function
;*******************************************************************************
Func H($x , $y , $z )
Return BitXOR($x , $y , $z)
EndFunc
;*******************************************************************************
; I (FUNCTION)
;
; DESCRIPTION:
; MD5's I function
;*******************************************************************************
Func I($x , $y , $z )
Return BitXOR($y , BitOR($x , (BitNOT($z))))
EndFunc
;*******************************************************************************
; FF (Func)
;
; DESCRIPTION:
; MD5's FF procedure
;*******************************************************************************
Func FF(ByRef $a , $b , $c , $d , $x , $s , $ac )
$a = AddUnsigned($a, AddUnsigned(AddUnsigned(F($b, $c, $d), $x), $ac))
$a = RotateLeft($a, $s)
$a = AddUnsigned($a, $b)
EndFunc
;*******************************************************************************
; GG (Func)
;
; DESCRIPTION:
; MD5's GG procedure
;*******************************************************************************
Func GG(ByRef $a , $b , $c , $d , $x , $s , $ac )
$a = AddUnsigned($a, AddUnsigned(AddUnsigned(G($b, $c, $d), $x), $ac))
$a = RotateLeft($a, $s)
$a = AddUnsigned($a, $b)
EndFunc
;*******************************************************************************
; HH (Func)
;
; DESCRIPTION:
; MD5's HH procedure
;*******************************************************************************
Func HH(ByRef $a , $b , $c , $d , $x , $s , $ac )
$a = AddUnsigned($a, AddUnsigned(AddUnsigned(H($b, $c, $d), $x), $ac))
$a = RotateLeft($a, $s)
$a = AddUnsigned($a, $b)
EndFunc
;*******************************************************************************
; II (Func)
;
; DESCRIPTION:
; MD5's II procedure
;*******************************************************************************
Func II(ByRef $a , $b , $c , $d , $x , $s , $ac )
$a = AddUnsigned($a, AddUnsigned(AddUnsigned(I($b, $c, $d), $x), $ac))
$a = RotateLeft($a, $s)
$a = AddUnsigned($a, $b)
EndFunc
;*******************************************************************************
; ConvertToWordArray (FUNCTION)
;
; PARAMETERS:
; (In/Out) - $sMessage - String - String message
;
; RETURN VALUE:
; Long() - Converted message as long array
;
; DESCRIPTION:
; Takes the string message and puts it in a long array with padding according to
; the MD5 rules.
;*******************************************************************************
Func ConvertToWordArray($sMessage )
Dim $lWordArray[1]
Const $MODULUS_BITS = 512
Const $CONGRUENT_BITS = 448
$lMessageLength = StringLen($sMessage)
[/autoit] [autoit][/autoit] [autoit]; Get padded number of words. Message needs to be congruent to 448 bits,
; modulo 512 bits. If it is exactly congruent to 448 bits, modulo 512 bits
; it must still have another 512 bits added. 512 bits = 64 bytes
; (or 16 * 4 byte words), 448 bits = 56 bytes. This means lMessageSize must
; be a multiple of 16 (i.e. 16 * 4 (bytes) * 8 (bits))
$lNumberOfWords = (int(($lMessageLength + _
int(($MODULUS_BITS - $CONGRUENT_BITS) / $BITS_TO_A_BYTE)) / _
int($MODULUS_BITS / $BITS_TO_A_BYTE)) + 1) * _
int($MODULUS_BITS / $BITS_TO_A_WORD)
ReDim $lWordArray[$lNumberOfWords]
; Combine each block of 4 bytes (ascii code of character) into one long
; value and store in the message. The high-order (most significant) bit of
; each byte is listed first. However, the low-order (least significant) byte
; is given first in each word.
$lBytePosition = 0
$lByteCount = 0
Do
; Each word is 4 bytes
$lWordCount = int($lByteCount / $BYTES_TO_A_WORD)
; The bytes are put in the word from the right most edge
$lBytePosition = (Mod($lByteCount , $BYTES_TO_A_WORD)) * $BITS_TO_A_BYTE
$lWordArray[$lWordCount] = BitOR($lWordArray[$lWordCount] , _
LShift(Asc(StringMid($sMessage, $lByteCount + 1, 1)), $lBytePosition))
$lByteCount = $lByteCount + 1
Until $lByteCount >= $lMessageLength
; Terminate according to MD5 rules with a 1 bit, zeros and the length in
; bits stored in the last two words
$lWordCount = int($lByteCount / $BYTES_TO_A_WORD)
$lBytePosition = (Mod($lByteCount , $BYTES_TO_A_WORD)) * $BITS_TO_A_BYTE
; Add a terminating 1 bit, all the rest of the bits to the end of the
; word array will default to zero
$lWordArray[$lWordCount] = BitOR($lWordArray[$lWordCount] , _
LShift(0x80, $lBytePosition))
; We put the length of the message in bits into the last two words, to get
; the length in bits we need to multiply by 8 (or left shift 3). This left
; shifted value is put in the first word. Any bits shifted off the left edge
; need to be put in the second word, we can work out which bits by shifting
; right the length by 29 bits.
$lWordArray[$lNumberOfWords - 2] = LShift($lMessageLength, 3)
$lWordArray[$lNumberOfWords - 1] = RShift($lMessageLength, 29)
Return $lWordArray
EndFunc
;*******************************************************************************
; WordToHex (FUNCTION)
;
; PARAMETERS:
; (In) - $lValue - Long - Long value to convert
;
; RETURN VALUE:
; String - Hex value to return
;
; DESCRIPTION:
; Takes a long integer and due to the bytes reverse order it extracts the
; individual bytes and converts them to hex appending them for an overall hex
; value
;*******************************************************************************
Func WordToHex($lValue)
$WordToHex=""
[/autoit] [autoit][/autoit] [autoit]For $lCount = 0 To 3
$lByte = BitAND(RShift($lValue, $lCount * $BITS_TO_A_BYTE) , _
$m_lOnBits[$BITS_TO_A_BYTE - 1])
$WordToHex = $WordToHex & StringRight("0" & Hex($lByte,2), 2)
Next
Return $WordToHex
EndFunc
;*******************************************************************************
; MD5 (FUNCTION)
;
; PARAMETERS:
; (In/Out) - sMessage - String - String to be digested
;
; RETURN VALUE:
; String - The MD5 digest
;
; DESCRIPTION:
; This function takes a string message and generates an MD5 digest for it.
; sMessage can be up to the VB string length limit of 2^31 (approx. 2 billion)
; characters.
;
; NOTE: Due to the way in which the string is processed the routine assumes a
; single byte character set. VB passes unicode (2-byte) character strings, the
; ConvertToWordArray function uses on the first byte for each character. This
; has been done this way for ease of use, to make the routine truely portable
; you could accept a byte array instead, it would then be up to the calling
; routine to make sure that the byte array is generated from their string in
; a manner consistent with the string type.
;*******************************************************************************
Func MD5($sMessage)
Const $S11 = 7
Const $S12 = 12
Const $S13 = 17
Const $S14 = 22
Const $S21 = 5
Const $S22 = 9
Const $S23 = 14
Const $S24 = 20
Const $S31 = 4
Const $S32 = 11
Const $S33 = 16
Const $S34 = 23
Const $S41 = 6
Const $S42 = 10
Const $S43 = 15
Const $S44 = 21
Class_Initialize()
[/autoit] [autoit][/autoit] [autoit]; Steps 1 and 2. Append padding bits and length and convert to words
$x = ConvertToWordArray($sMessage)
; Step 3. Initialise
$a = 0x67452301
$b = 0xEFCDAB89
$c = 0x98BADCFE
$d = 0x10325476
; Step 4. Process the message in 16-word blocks
For $k = 0 To UBound($x)-1 Step 16
$AA = $a
$BB = $b
$CC = $c
$DD = $d
; The hex number on the end of each of the following procedure calls is
; an element from the 64 element table constructed with
; T(i) = Int(4294967296 * Abs(Sin(i))) where i is 1 to 64.
;
; However, for speed we don't want to calculate the value every time.
FF( $a, $b, $c, $d, $x[$k + 0], $S11, 0xD76AA478 )
FF( $d, $a, $b, $c, $x[$k + 1], $S12, 0xE8C7B756 )
FF( $c, $d, $a, $b, $x[$k + 2], $S13, 0x242070DB )
FF( $b, $c, $d, $a, $x[$k + 3], $S14, 0xC1BDCEEE )
FF( $a, $b, $c, $d, $x[$k + 4], $S11, 0xF57C0FAF )
FF( $d, $a, $b, $c, $x[$k + 5], $S12, 0x4787C62A )
FF( $c, $d, $a, $b, $x[$k + 6], $S13, 0xA8304613 )
FF( $b, $c, $d, $a, $x[$k + 7], $S14, 0xFD469501 )
FF( $a, $b, $c, $d, $x[$k + 8], $S11, 0x698098D8 )
FF( $d, $a, $b, $c, $x[$k + 9], $S12, 0x8B44F7AF )
FF( $c, $d, $a, $b, $x[$k + 10], $S13, 0xFFFF5BB1)
FF( $b, $c, $d, $a, $x[$k + 11], $S14, 0x895CD7BE)
FF( $a, $b, $c, $d, $x[$k + 12], $S11, 0x6B901122)
FF( $d, $a, $b, $c, $x[$k + 13], $S12, 0xFD987193)
FF( $c, $d, $a, $b, $x[$k + 14], $S13, 0xA679438E)
FF( $b, $c, $d, $a, $x[$k + 15], $S14, 0x49B40821)
GG( $a, $b, $c, $d, $x[$k + 1], $S21, 0xF61E2562 )
GG( $d, $a, $b, $c, $x[$k + 6], $S22, 0xC040B340 )
GG( $c, $d, $a, $b, $x[$k + 11], $S23, 0x265E5A51)
GG( $b, $c, $d, $a, $x[$k + 0], $S24, 0xE9B6C7AA )
GG( $a, $b, $c, $d, $x[$k + 5], $S21, 0xD62F105D )
GG( $d, $a, $b, $c, $x[$k + 10], $S22, 0x2441453 )
GG( $c, $d, $a, $b, $x[$k + 15], $S23, 0xD8A1E681)
GG( $b, $c, $d, $a, $x[$k + 4], $S24, 0xE7D3FBC8 )
GG( $a, $b, $c, $d, $x[$k + 9], $S21, 0x21E1CDE6 )
GG( $d, $a, $b, $c, $x[$k + 14], $S22, 0xC33707D6)
GG( $c, $d, $a, $b, $x[$k + 3], $S23, 0xF4D50D87 )
GG( $b, $c, $d, $a, $x[$k + 8], $S24, 0x455A14ED )
GG( $a, $b, $c, $d, $x[$k + 13], $S21, 0xA9E3E905)
GG( $d, $a, $b, $c, $x[$k + 2], $S22, 0xFCEFA3F8 )
GG( $c, $d, $a, $b, $x[$k + 7], $S23, 0x676F02D9 )
GG( $b, $c, $d, $a, $x[$k + 12], $S24, 0x8D2A4C8A)
HH( $a, $b, $c, $d, $x[$k + 5], $S31, 0xFFFA3942 )
HH( $d, $a, $b, $c, $x[$k + 8], $S32, 0x8771F681 )
HH( $c, $d, $a, $b, $x[$k + 11], $S33, 0x6D9D6122)
HH( $b, $c, $d, $a, $x[$k + 14], $S34, 0xFDE5380C)
HH( $a, $b, $c, $d, $x[$k + 1], $S31, 0xA4BEEA44 )
HH( $d, $a, $b, $c, $x[$k + 4], $S32, 0x4BDECFA9 )
HH( $c, $d, $a, $b, $x[$k + 7], $S33, 0xF6BB4B60 )
HH( $b, $c, $d, $a, $x[$k + 10], $S34, 0xBEBFBC70)
HH( $a, $b, $c, $d, $x[$k + 13], $S31, 0x289B7EC6)
HH( $d, $a, $b, $c, $x[$k + 0], $S32, 0xEAA127FA )
HH( $c, $d, $a, $b, $x[$k + 3], $S33, 0xD4EF3085 )
HH( $b, $c, $d, $a, $x[$k + 6], $S34, 0x4881D05 )
HH( $a, $b, $c, $d, $x[$k + 9], $S31, 0xD9D4D039 )
HH( $d, $a, $b, $c, $x[$k + 12], $S32, 0xE6DB99E5)
HH( $c, $d, $a, $b, $x[$k + 15], $S33, 0x1FA27CF8)
HH( $b, $c, $d, $a, $x[$k + 2], $S34, 0xC4AC5665 )
II( $a, $b, $c, $d, $x[$k + 0], $S41, 0xF4292244 )
II( $d, $a, $b, $c, $x[$k + 7], $S42, 0x432AFF97 )
II( $c, $d, $a, $b, $x[$k + 14], $S43, 0xAB9423A7)
II( $b, $c, $d, $a, $x[$k + 5], $S44, 0xFC93A039 )
II( $a, $b, $c, $d, $x[$k + 12], $S41, 0x655B59C3)
II( $d, $a, $b, $c, $x[$k + 3], $S42, 0x8F0CCC92 )
II( $c, $d, $a, $b, $x[$k + 10], $S43, 0xFFEFF47D)
II( $b, $c, $d, $a, $x[$k + 1], $S44, 0x85845DD1 )
II( $a, $b, $c, $d, $x[$k + 8], $S41, 0x6FA87E4F )
II( $d, $a, $b, $c, $x[$k + 15], $S42, 0xFE2CE6E0)
II( $c, $d, $a, $b, $x[$k + 6], $S43, 0xA3014314 )
II( $b, $c, $d, $a, $x[$k + 13], $S44, 0x4E0811A1)
II( $a, $b, $c, $d, $x[$k + 4], $S41, 0xF7537E82 )
II( $d, $a, $b, $c, $x[$k + 11], $S42, 0xBD3AF235)
II( $c, $d, $a, $b, $x[$k + 2], $S43, 0x2AD7D2BB )
II( $b, $c, $d, $a, $x[$k + 9], $S44, 0xEB86D391 )
$a = AddUnsigned($a, $AA)
$b = AddUnsigned($b, $BB)
$c = AddUnsigned($c, $CC)
$d = AddUnsigned($d, $DD)
Next
; Step 5. Output the 128 bit digest
Return StringLower(WordToHex($a) & WordToHex($b) & WordToHex($c) & WordToHex($d))
EndFunc