It works around a few bugs the OS X version of PureBasic has. The functionality is the same as the original with the difference that the callback procedure has to be a ProcedureC instead of a Procedure.
Code: Select all
;================================================================
;
; Library Commands: Sha256FingerPrint()
; Sha256FileFingerPrint()
; Sha224FingerPrint()
; Sha224FileFingerPrint()
;
; Author: Lloyd Gallant (netmaestro)
; adapted for OS X by Wilbert
;
; Contributors: Thanks to Danilo and kenmo for
; help with the ROTR and SHR macros,
; idle and wilbert for their help
; with asm routines.
; and to Christopher Devine for the
; c code this program is based on.
;
; Date: August 7, 2011
; Target Compiler: Purebasic 4 and up
; Target OS: Windows, Linux, MacOS
;
; License: GNU General Public License
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License As published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY Or FITNESS For A PARTICULAR PURPOSE. See the
; GNU General Public License For more details.
;
; The logic for this program is based on sha256.c found here:
;
; http://www.spale.com/download/scrypt/scrypt1.0/
;
; You can test the accuracy of this program by generating
; test data at:
;
; http://hashgenerator.de/
;
;================================================================
;
;
; Usage:
;
; result$ = SHA256Fingerprint(*address, length, [ ,*progress ] )
; result$ = SHA256FileFingerprint(file$, [ ,*progress ] )
;
; result$ = SHA224Fingerprint(*address, length, [ ,*progress ] )
; result$ = SHA224FileFingerprint(file$, [ ,*progress ] )
;
; Progress callback function:
;
; ProcedureC MyCallBack(value.i)
; ; value is 0 to 100 representing percentage completed
; Endprocedure
;
;
;================================================================
; STRUCTURE
;================================================================
Structure sha256_context
state.l [8] ; offset 0
buffer.a [64] ; offset 32
padding.a [64] ; offset 96
processed.q ; offset 160
jobsize.q ; offset 168
digestlen.l ; offset 176
callback.l ; offset 180
EndStructure
;================================================================
; HELPER MACROS
;================================================================
Macro S256_R_(t)
!mov ebx, [ebp+(4*t)]
!bswap ebx
!mov [esp+(4*t)], ebx
EndMacro
Macro S256_R(t)
!mov ebx, [esp+(4*t)-64]
!mov eax, [esp+(4*t)-60]
!add ebx, [esp+(4*t)-28]
!mov ecx, eax
!mov edx, eax
!ror eax, 7
!ror ecx, 18
!shr edx, 3
!xor eax, ecx
!xor eax, edx
!add ebx, eax
!mov eax, [esp+(4*t)-8]
!mov ecx, eax
!mov edx, eax
!ror eax, 17
!ror ecx, 19
!shr edx, 10
!xor eax, ecx
!xor eax, edx
!add ebx, eax
!mov [esp+(4*t)], ebx
EndMacro
Macro S256_P(a,b,c,d,e,f,g,h,x,K)
!movd edx, e
!movd eax, h ; h = h + Sigma3(e) + F1(e,f,g) + K + x
!add ebx, eax
!add ebx, k
!mov eax, edx ; Sigma 3
!mov ecx, eax
!ror eax, 6
!ror ecx, 11
!xor eax, ecx
!ror ecx, 14
!xor eax, ecx
!add ebx, eax
!movq h, f; F1
!pxor h, g
!pand h, e
!pxor h, g
!movd e, ebx
!paddd h, e
!paddd d, h ; d = d + h
!movq e, a; F0 ; h = h + Sigma2(a) + F0(a,b,c)
!por e, b
!pand e, c
!movd eax, a
!pand a, b
!por e, a
!movd a, eax
!paddd h, e
!mov ecx, eax ; Sigma 2
!ror eax, 2
!ror ecx, 13
!xor eax, ecx
!ror ecx, 9
!xor eax, ecx
!movd e, eax
!paddd h,e
!movd e, edx
EndMacro
;================================================================
; LOCAL FUNCTIONS
;================================================================
Procedure sha224_starts( *ctx.sha256_context )
*ctx\state[0] = $c1059ed8
*ctx\state[1] = $367cd507
*ctx\state[2] = $3070dd17
*ctx\state[3] = $f70e5939
*ctx\state[4] = $ffc00b31
*ctx\state[5] = $68581511
*ctx\state[6] = $64f98fa7
*ctx\state[7] = $befa4fa4
*ctx\digestlen = 28
EndProcedure
Procedure sha256_starts( *ctx.sha256_context )
*ctx\state[0] = $6A09E667
*ctx\state[1] = $BB67AE85
*ctx\state[2] = $3C6EF372
*ctx\state[3] = $A54FF53A
*ctx\state[4] = $510E527F
*ctx\state[5] = $9B05688C
*ctx\state[6] = $1F83D9AB
*ctx\state[7] = $5BE0CD19
*ctx\digestlen = 32
EndProcedure
Procedure sha256_process_addr__()
!mov eax, sha256_process_start
ProcedureReturn
!sha256_process_start:
!sub esp, 12
!mov [esp ], ebx
!mov [esp + 4], esi
!mov [esp + 8], ebp
!mov esi, [esp + 16] ; *ctx
!mov ebp, [esp + 20] ; *bytes
!sub esp, 256 ; Allocate 256 bytes of memory for 64 dwords
!movd mm0, [esi ]
!movd mm1, [esi + 4]
!movd mm2, [esi + 8]
!movd mm3, [esi + 12]
!movd mm4, [esi + 16]
!movd mm5, [esi + 20]
!movd mm6, [esi + 24]
!movd mm7, [esi + 28]
!sha256_process_loop:
S256_R_(0)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 0, 0x428A2F98 )
S256_R_(1)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 1, 0x71374491 )
S256_R_(2)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 2, 0xB5C0FBCF )
S256_R_(3)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 3, 0xE9B5DBA5 )
S256_R_(4)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 4, 0x3956C25B )
S256_R_(5)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 5, 0x59F111F1 )
S256_R_(6)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 6, 0x923F82A4 )
S256_R_(7)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 7, 0xAB1C5ED5 )
S256_R_(8)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 8, 0xD807AA98 )
S256_R_(9)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 9, 0x12835B01 )
S256_R_(10)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 10, 0x243185BE )
S256_R_(11)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 11, 0x550C7DC3 )
S256_R_(12)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 12, 0x72BE5D74 )
S256_R_(13)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 13, 0x80DEB1FE )
S256_R_(14)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 14, 0x9BDC06A7 )
S256_R_(15)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 15, 0xC19BF174 )
S256_R(16)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 16, 0xE49B69C1 )
S256_R(17)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 17, 0xEFBE4786 )
S256_R(18)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 18, 0x0FC19DC6 )
S256_R(19)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 19, 0x240CA1CC )
S256_R(20)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 20, 0x2DE92C6F )
S256_R(21)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 21, 0x4A7484AA )
S256_R(22)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 22, 0x5CB0A9DC )
S256_R(23)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 23, 0x76F988DA )
S256_R(24)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 24, 0x983E5152 )
S256_R(25)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 25, 0xA831C66D )
S256_R(26)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 26, 0xB00327C8 )
S256_R(27)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 27, 0xBF597FC7 )
S256_R(28)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 28, 0xC6E00BF3 )
S256_R(29)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 29, 0xD5A79147 )
S256_R(30)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 30, 0x06CA6351 )
S256_R(31)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 31, 0x14292967 )
S256_R(32)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 32, 0x27B70A85 )
S256_R(33)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 33, 0x2E1B2138 )
S256_R(34)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 34, 0x4D2C6DFC )
S256_R(35)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 35, 0x53380D13 )
S256_R(36)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 36, 0x650A7354 )
S256_R(37)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 37, 0x766A0ABB )
S256_R(38)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 38, 0x81C2C92E )
S256_R(39)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 39, 0x92722C85 )
S256_R(40)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 40, 0xA2BFE8A1 )
S256_R(41)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 41, 0xA81A664B )
S256_R(42)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 42, 0xC24B8B70 )
S256_R(43)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 43, 0xC76C51A3 )
S256_R(44)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 44, 0xD192E819 )
S256_R(45)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 45, 0xD6990624 )
S256_R(46)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 46, 0xF40E3585 )
S256_R(47)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 47, 0x106AA070 )
S256_R(48)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 48, 0x19A4C116 )
S256_R(49)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 49, 0x1E376C08 )
S256_R(50)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 50, 0x2748774C )
S256_R(51)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 51, 0x34B0BCB5 )
S256_R(52)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 52, 0x391C0CB3 )
S256_R(53)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 53, 0x4ED8AA4A )
S256_R(54)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 54, 0x5B9CCA4F )
S256_R(55)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 55, 0x682E6FF3 )
S256_R(56)
S256_P( mm0, mm1, mm2, mm3, mm4, mm5, mm6, mm7, 56, 0x748F82EE )
S256_R(57)
S256_P( mm7, mm0, mm1, mm2, mm3, mm4, mm5, mm6, 57, 0x78A5636F )
S256_R(58)
S256_P( mm6, mm7, mm0, mm1, mm2, mm3, mm4, mm5, 58, 0x84C87814 )
S256_R(59)
S256_P( mm5, mm6, mm7, mm0, mm1, mm2, mm3, mm4, 59, 0x8CC70208 )
S256_R(60)
S256_P( mm4, mm5, mm6, mm7, mm0, mm1, mm2, mm3, 60, 0x90BEFFFA )
S256_R(61)
S256_P( mm3, mm4, mm5, mm6, mm7, mm0, mm1, mm2, 61, 0xA4506CEB )
S256_R(62)
S256_P( mm2, mm3, mm4, mm5, mm6, mm7, mm0, mm1, 62, 0xBEF9A3F7 )
S256_R(63)
S256_P( mm1, mm2, mm3, mm4, mm5, mm6, mm7, mm0, 63, 0xC67178F2 )
!paddd mm0, [esi ]
!movd [esi ], mm0
!paddd mm1, [esi + 4]
!movd [esi + 4], mm1
!paddd mm2, [esi + 8]
!movd [esi + 8], mm2
!paddd mm3, [esi + 12]
!movd [esi + 12], mm3
!paddd mm4, [esi + 16]
!movd [esi + 16], mm4
!paddd mm5, [esi + 20]
!movd [esi + 20], mm5
!paddd mm6, [esi + 24]
!movd [esi + 24], mm6
!paddd mm7, [esi + 28]
!movd [esi + 28], mm7
!add ebp, 64
!dec dword [esp + 24 + 256]
!jnz sha256_process_loop
!add esp, 256
!mov ebx, [esp ]
!mov esi, [esp + 4]
!mov ebp, [esp + 8]
!add esp, 12
!emms
!ret
EndProcedure
Procedure sha256_swap_endian_addr__()
!mov eax, sha256_swap_endian_start
ProcedureReturn
!sha256_swap_endian_start:
!mov edx, [esp + 4]
!mov eax, [esp + 8]
!bswap eax
!bswap edx
!ret
EndProcedure
Procedure sha256_set_digest_addr__()
!mov eax, sha256_set_digest_start
ProcedureReturn
!sha256_set_digest_start:
!push ebx
!mov ebx, [esp + 8]
!mov edx, [esp + 12]
!mov ecx, [ebx + 176]
!dec ecx
!sha256_set_digest_loop:
!xor ecx, 3
!mov al, [ebx + ecx]
!xor ecx, 3
!mov ah, al
!shr ah, 4
!and ax, 0x0f0f
!or ax, 0x9090
!daa
!adc al, 0x40
!daa
!ror ax, 8
!daa
!adc al, 0x40
!daa
!or ax, 0x2020
!mov [edx + ecx * 2], ax
!sub ecx, 1
!jnc sha256_set_digest_loop
!pop ebx
!ret
EndProcedure
PrototypeC sha256_process_proto(*ctx, *bytes, blocks)
PrototypeC.q sha256_swap_endian_proto(value.q)
PrototypeC sha256_set_digest_proto(*ctx, *output)
Global sha256_process.sha256_process_proto = sha256_process_addr__()
Global sha256_swap_endian.sha256_swap_endian_proto = sha256_swap_endian_addr__()
Global sha256_set_digest.sha256_set_digest_proto = sha256_set_digest_addr__()
Procedure sha256_update(*ctx.sha256_context, *input, length)
Protected left, fill, blocks, blocks_1M
Protected processed.q = *ctx\processed
If length = 0 : ProcedureReturn : EndIf
left = *ctx\processed & $3f
fill = 64 - left
*ctx\processed + length
If left And length >= fill
CopyMemory(*input, @*ctx\buffer + left, fill)
sha256_process(*ctx, @*ctx\buffer, 1)
length - fill
*input + fill
left = 0
EndIf
blocks = length >> 6
length & $3f
If blocks
blocks_1M = blocks >> 14
blocks & $3fff
While blocks_1M
sha256_process(*ctx, *input, $4000)
blocks_1M - 1
*input + $100000
If *ctx\callback
processed + $100000
CallCFunctionFast(*ctx\callback, 100 * processed / *ctx\jobsize)
EndIf
Wend
sha256_process(*ctx, *input, blocks)
*input + blocks << 6
If *ctx\callback
processed + blocks << 6
CallCFunctionFast(*ctx\callback, 100 * processed / *ctx\jobsize)
EndIf
EndIf
If length
CopyMemory(*input, @*ctx\buffer + left, length)
EndIf
EndProcedure
Procedure sha256_finish(*ctx.sha256_context, *output)
Protected msglen.q, padn
*ctx\padding[0] = $80
padn = 56 - *ctx\processed & 63
If padn <= 0 : padn + 64 : EndIf
msglen = sha256_swap_endian(*ctx\jobsize << 3)
sha256_update(*ctx, @*ctx\padding, padn)
sha256_update(*ctx, @msglen, 8)
sha256_set_digest(*ctx, *output)
If *ctx\callback
CallCFunctionFast(*ctx\callback, 100)
EndIf
EndProcedure
Procedure.s SHA256LongFingerprint(*datapointer, length, full, *callback = 0) ; Data address, data size, [ ,<procaddress> ]
Protected digest.s
Protected *output, *ctx.sha256_context
*ctx = AllocateMemory(SizeOf(sha256_context))
*ctx\jobsize = length
*ctx\callback = *callback
*output = AllocateMemory(64)
If full
sha256_starts(*ctx)
Else
sha224_starts(*ctx)
EndIf
sha256_update(*ctx, *datapointer, length)
sha256_finish(*ctx, *output)
digest = PeekS(*output, *ctx\digestlen << 1, #PB_Ascii)
FreeMemory(*output)
FreeMemory(*ctx)
ProcedureReturn digest
EndProcedure
Procedure.s SHA256LongFileFingerprint(filename.s, full, *callback = 0) ; filename$, [ ,<procaddress> ]
Protected digest.s
Protected *datapointer, *output, *ctx.sha256_context
Protected bytesread, fresult
fresult = OpenFile(#PB_Any, filename)
If fresult
*ctx = AllocateMemory(SizeOf(sha256_context))
*ctx\jobsize = Lof(fresult)
*ctx\callback = *callback
*datapointer = AllocateMemory($40000)
*output = AllocateMemory(64)
If full
sha256_starts(*ctx)
Else
sha224_starts(*ctx)
EndIf
While Not Eof(fresult)
bytesread = ReadData(fresult, *datapointer, $40000)
sha256_update(*ctx, *datapointer, bytesread)
Wend
CloseFile(fresult)
sha256_finish(*ctx, *output)
digest = PeekS(*output, *ctx\digestlen << 1, #PB_Ascii)
FreeMemory(*output)
FreeMemory(*datapointer)
FreeMemory(*ctx)
EndIf
ProcedureReturn digest
EndProcedure
;================================================================
; EXPORTED FUNCTIONS
;================================================================
ProcedureDLL.s SHA256FileFingerprint(filename.s, *callback = 0) ; filename$, [ ,<procaddress> ]
ProcedureReturn SHA256LongFileFingerprint(filename.s, 1, *callback)
EndProcedure
ProcedureDLL.s SHA224FileFingerprint(filename.s, *callback = 0) ; filename$, [ ,<procaddress> ]
ProcedureReturn SHA256LongFileFingerprint(filename.s, 0, *callback)
EndProcedure
ProcedureDLL.s SHA256Fingerprint(*datapointer, Length, *callback = 0) ; Data address, data size, [ ,<procaddress> ]
ProcedureReturn SHA256LongFingerprint(*datapointer, Length, 1, *callback)
EndProcedure
ProcedureDLL.s SHA224Fingerprint(*datapointer, Length, *callback = 0) ; Data address, data size, [ ,<procaddress> ]
ProcedureReturn SHA256LongFingerprint(*datapointer, Length, 0, *callback)
EndProcedure