SHA256/224 Fingerprint and FileFingerprint

Share your advanced PureBasic knowledge/code with the community.
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

SHA256/224 Fingerprint and FileFingerprint

Post by netmaestro »

Notes:

August 8: Added SHA256FileFingerprint( filename$, [ ,*progress ] )

August 15: Program is updated to be faster and SHA256FileFingerprint will now handle files > 2gb in size.

August 15: Added two commands, SHA224Fingerprint() and SHA224FileFingerprint()

August 16: Optimized the code by replacing procedures with inlined asm, program is faster now

August 17: Significant speed upgrade today, almost all the sha256_process() procedure is rewritten in asm to use registers instead of variables for the states

August 30: Wilbert has created a MacOS-friendly version of this program, you can find it here:http://www.purebasic.fr/english/viewtop ... 19&t=47388

When I first wrote this program, it was all Purebasic code. It ran fine. However, in the course of testing sha256FileFingerprint for accuracy I tested the result against
that produced by the Hashslash file hasher, and I was dismayed to find that the 50mb file I was testing with took 24 seconds with my code and Hashslash had it done
in 4.5 seconds. So back to the drawingboard and quite some lines of inlined asm later, the code now processes the 50mb in under 3 seconds. Take that, Hashslash!

Also, for some reason the code will no longer run after compiling with Tailbite. So that option is gone for now, just use as an include.

If you are using a progress bar or such (unnecessary for data less than about 50+ mb) it should be written like so:

Code: Select all

Procedure progress(value)
  Static lastvalue
  If value<>lastvalue
   ; StatusBarProgress(0,0,value)
    lastvalue=value
  EndIf
EndProcedure

Code: Select all

;================================================================
;
; Library Commands:         Sha256FingerPrint()
;                           Sha256FileFingerPrint()
;                           Sha224FingerPrint()
;                           Sha224FileFingerPrint()
;
; Author:                   Lloyd Gallant (netmaestro)
;
; 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:
;
; Procedure MyCallBack(value.i)
;   ; value is 0 to 100 representing percentage completed
; Endprocedure 
;
;
;================================================================
;                      STRUCTURES                      
;================================================================

Structure UINT8_BUFFER
  b.a[64]
EndStructure

Structure sha256_context
  state.l  [8]
  buffer.a [64]
  total.q  
  totalprocessed.q
EndStructure

;================================================================
;                      HELPER MACROS                     
;================================================================

Macro R_(t)
  !mov ebx, [ebp+(4*t)]
  !bswap ebx
  !mov [edi+(4*t)], ebx  
EndMacro

Macro R(t)
  !mov ebx, [edi+(4*t)-64]     
  !add ebx, [edi+(4*t)-28]     
  
  !mov eax, [edi+(4*t)-60]
  !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, [edi+(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 [edi+(4*t)], ebx
EndMacro

Macro P(a,b,c,d,e,f,g,h,x,K)
  
  !movd eax, h  ;   h = h + Sigma3(e) + F1(e,f,g) + K + x
  !add ebx, eax 
  !add ebx, k
  
  !movd eax, e ; F1
  !movd edx, f
  !movd ecx, g
  !xor edx, ecx
  !and edx, eax           
  !xor edx, ecx
  !add ebx, edx       
  
  !movd eax, e ; Sigma3
  !mov edx, eax
  !mov ecx, eax
  !ror eax, 6
  !ror edx, 11
  !ror ecx, 25
  !xor eax, edx
  !xor eax, ecx
  !add ebx, eax
  !movd h, ebx
  !paddd d, h   ; d = d + h
  
  !movd eax, a ; F0  ; h = h + Sigma2(a) + F0(a,b,c) 
  !movd edx, b
  !movd ecx, c
  !or  eax, edx
  !and eax, ecx           
  !movd ecx, a
  !and ecx, edx
  !or  eax, ecx
  !add ebx, eax
  
  !movd eax, a ; Sigma2
  !mov edx, eax
  !mov ecx, eax
  !ror eax, 2
  !ror edx, 13
  !ror ecx, 22
  !xor eax, edx
  !xor eax, ecx
  !add ebx, eax
  !movd h, ebx
  
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\totalprocessed=0
  
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\totalprocessed=0
  
EndProcedure

Procedure sha256_process_addr__()
  
  !mov eax, sha256_process_start
  ProcedureReturn
  !sha256_process_start:
  
  !push ebp
  !push ebx
  !push edi
  !push esi
  
  !mov esi, [esp+20] ; *ctx
  !mov ebp, [esp+24] ; *bytes
  
  !sub esp, 272 ; Allocate 256 bytes of memory for 64 dwords
  !mov edi, esp
  !add edi, 15
  !and edi, 0xfffffff0
  
  !movd xmm0, [esi]
  !movd xmm1, [esi+4]
  !movd xmm2, [esi+8]
  !movd xmm3, [esi+12]
  !movd xmm4, [esi+16]
  !movd xmm5, [esi+20]
  !movd xmm6, [esi+24]
  !movd xmm7, [esi+28]
  
  R_(0)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,  0, 0x428A2F98 )
  R_(1)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6,  1, 0x71374491 )
  R_(2)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5,  2, 0xB5C0FBCF )
  R_(3)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4,  3, 0xE9B5DBA5 )
  R_(4)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3,  4, 0x3956C25B )
  R_(5)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2,  5, 0x59F111F1 )
  R_(6)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1,  6, 0x923F82A4 )
  R_(7)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0,  7, 0xAB1C5ED5 )
  R_(8)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7,  8, 0xD807AA98 )
  R_(9)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6,  9, 0x12835B01 )
  R_(10)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 10, 0x243185BE )
  R_(11)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 11, 0x550C7DC3 )
  R_(12)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 12, 0x72BE5D74 )
  R_(13)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 13, 0x80DEB1FE )
  R_(14)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 14, 0x9BDC06A7 )
  R_(15)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 15, 0xC19BF174 )
  R(16)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 16, 0xE49B69C1 )
  R(17)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, 17, 0xEFBE4786 )
  R(18)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 18, 0x0FC19DC6 )
  R(19)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 19, 0x240CA1CC )
  R(20)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 20, 0x2DE92C6F )
  R(21)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 21, 0x4A7484AA )
  R(22)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 22, 0x5CB0A9DC )
  R(23)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 23, 0x76F988DA )
  R(24)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 24, 0x983E5152 )
  R(25)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, 25, 0xA831C66D )
  R(26)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 26, 0xB00327C8 )
  R(27)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 27, 0xBF597FC7 )
  R(28)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 28, 0xC6E00BF3 )
  R(29)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 29, 0xD5A79147 )
  R(30)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 30, 0x06CA6351 )
  R(31)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 31, 0x14292967 )
  R(32)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 32, 0x27B70A85 )
  R(33)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, 33, 0x2E1B2138 )
  R(34)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 34, 0x4D2C6DFC )
  R(35)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 35, 0x53380D13 )
  R(36)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 36, 0x650A7354 )
  R(37)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 37, 0x766A0ABB )
  R(38)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 38, 0x81C2C92E )
  R(39)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 39, 0x92722C85 )
  R(40)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 40, 0xA2BFE8A1 )
  R(41)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, 41, 0xA81A664B )
  R(42)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 42, 0xC24B8B70 )
  R(43)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 43, 0xC76C51A3 )
  R(44)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 44, 0xD192E819 )
  R(45)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 45, 0xD6990624 )
  R(46)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 46, 0xF40E3585 )
  R(47)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 47, 0x106AA070 )
  R(48)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 48, 0x19A4C116 )
  R(49)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, 49, 0x1E376C08 )
  R(50)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 50, 0x2748774C )
  R(51)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 51, 0x34B0BCB5 )
  R(52)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 52, 0x391C0CB3 )
  R(53)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 53, 0x4ED8AA4A )
  R(54)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 54, 0x5B9CCA4F )
  R(55)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 55, 0x682E6FF3 )
  R(56)
  P( xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, 56, 0x748F82EE )
  R(57)
  P( xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, 57, 0x78A5636F )
  R(58)
  P( xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, 58, 0x84C87814 )
  R(59)
  P( xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, xmm4, 59, 0x8CC70208 )
  R(60)
  P( xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, xmm3, 60, 0x90BEFFFA )
  R(61)
  P( xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, xmm2, 61, 0xA4506CEB )
  R(62)
  P( xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, xmm1, 62, 0xBEF9A3F7 )
  R(63)
  P( xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm0, 63, 0xC67178F2 )

  !movd edx, xmm0
  !add [esi +  0], edx
  !movd edx, xmm1
  !add [esi +  4], edx
  !movd edx, xmm2
  !add [esi +  8], edx
  !movd edx, xmm3
  !add [esi + 12], edx
  !movd edx, xmm4
  !add [esi + 16], edx
  !movd edx, xmm5
  !add [esi + 20], edx
  !movd edx, xmm6
  !add [esi + 24], edx
  !movd edx, xmm7
  !add [esi + 28], edx
  
  !add esp, 272 
  !pop esi
  !pop edi
  !pop ebx
  !pop ebp
  !ret
  
EndProcedure

PrototypeC sha256_process_proto(*ctx.sha256_context, *bytes)
Global sha256_process.sha256_process_proto = sha256_process_addr__()

Procedure sha256_update( *ctx.sha256_context, *input, length, jobsize.q, *callback )  
  
  Define.l left, fill
  
  If length=0 : ProcedureReturn : EndIf
  
  left = *ctx\total & $3F
  fill = 64-left
  
  *ctx\total + length
  
  If left And (length >= fill)
    CopyMemory( *input, @*ctx\buffer[0]+left, fill )
    sha256_process( *ctx, @*ctx\buffer[0] )
    length - fill
    *input + fill
    left = 0
  EndIf
  
  While length >= 64 
    sha256_process( *ctx, *input )
    length - 64
    *input + 64
    *ctx\totalprocessed+64
    
    If *callback
      If *ctx\totalprocessed & $ffff = 0
        progress = 100 * *ctx\totalprocessed / jobsize
        CallFunctionFast(*callback, progress )
      EndIf
    EndIf
    
  Wend
  
  If length 
    CopyMemory(  *input, @*ctx\buffer[0]+left, length )
  EndIf
 
EndProcedure

Procedure sha256_finish( *ctx.sha256_context, *digest, jobsize.q, full, *callback )
  
  Define.l last, padn
  msglen.q
  sha256_padding.UINT8_BUFFER
  sha256_padding\b[0]=$80
  
  jobsize<<3
  !mov  eax, [p.v_jobsize+4]
  !mov  edx, [p.v_jobsize]
  !bswap eax
  !bswap edx
  !mov [p.v_msglen],eax
  !mov [p.v_msglen+4],edx
  
  last = *ctx\total & $3F
  
  If last<56
    padn = 56-last
  Else
    padn = 120-last
  EndIf
  
  sha256_update( *ctx, @sha256_padding, padn, padn, *callback )
  sha256_update( *ctx, @msglen, 8, 8, *callback )
  
  !push edi
  !push esi
  !mov esi, [p.p_ctx+8]
  !mov edi, [p.p_digest+8] 
  !xor ecx, ecx
  !loopstart:
  !mov eax, [esi]
  !bswap eax
  !mov [edi + ecx], eax
  !add ecx, 4  
  !add esi, 4
  !cmp ecx, 32
  !jnz loopstart
  !pop esi
  !pop edi
  
  *ctx\totalprocessed = 0
  
   If *callback
     CallFunctionFast(*callback, 100 )
   EndIf
  
EndProcedure

Procedure MoveSumToDigestAsHex(*sum, *digest, full)
  !push edi
  !push esi
  !cmp dword [esp + 20], 0x0
  !jnz fullsize
  !mov ecx, 0x1c
  !jmp endsize
  !fullsize:
  !mov ecx, 0x20
  !endsize:
  !mov esi, [esp + 12]
  !mov edi, [esp + 16]
  !jecxz exit
  !startloop:
  !lodsb
  !mov ah, al
  !shr al, 4
  !and ax, 0x0f0f
  !or ax, 0x3030  
  !cmp al, 0x3a
  !jb no_offset_lo
  !add al, 39
  !no_offset_lo:
  !cmp ah, 0x3a
  !jb no_offset_hi
  !add ah, 39
  !no_offset_hi:
  !stosw
  !loop startloop
  !exit:
  !pop esi
  !pop edi
EndProcedure

Procedure.s SHA256LongFingerprint(*datapointer, Length, full, *callback=0) ; Data address, data size, [ ,<procaddress> ]
  
  *ctx.sha256_context = AllocateMemory(SizeOf(sha256_context))
  *sha256sum = AllocateMemory(32)
  
  Protected digest.s
  If full
    sha256_starts( *ctx )
  Else
    sha224_starts( *ctx )
  EndIf
  
  sha256_update( *ctx, *datapointer, Length, Length, *callback )
  sha256_finish( *ctx, *sha256sum, Length, full, *callback )
  
  *output = AllocateMemory(65)
  
  MoveSumToDigestAsHex(*sha256sum, *output, full)
  
  digest = PeekS(*output)
  
  FreeMemory(*output)
  FreeMemory(*sha256sum)
  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
  Protected jobsize.q
  
  *ctx           = AllocateMemory(SizeOf(sha256_context))
  *sha256sum     = AllocateMemory(32)
  *output        = AllocateMemory(65)
  *datapointer   = AllocateMemory($10000)
  fresult        = OpenFile(#PB_Any, filename)
  
  If fresult
    FileBuffersSize(fresult, $10000)
    jobsize = Lof(fresult)
    
    If full
      sha256_starts( *ctx )
    Else
      sha224_starts( *ctx )
    EndIf
    
    While Not Eof(fresult)
      bytesread = ReadData(fresult, *datapointer, $10000)
      sha256_update( *ctx, *datapointer, bytesread, jobsize, *callback )
    Wend
    sha256_finish( *ctx, *sha256sum, jobsize, full, *callback )
    
    MoveSumToDigestAsHex(*sha256sum, *output, full)
    
    digest = PeekS(*output)
    CloseFile(fresult)
  EndIf
  
  FreeMemory(*datapointer)
  FreeMemory(*output)
  FreeMemory(*sha256sum)
  FreeMemory(*ctx)
  
  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

And a test program:

Code: Select all

; Test program for SHA256Fingerprint()

; Here are some common tests with known outputs:

IncludeFile "sha256.pbi"

ProcedureDLL.l TicksHQ() ; By Rescator
  Static maxfreq.q 
  Protected t.q   
  If maxfreq=0 
    QueryPerformanceFrequency_(@maxfreq) 
    maxfreq=maxfreq/1000
  EndIf 
  QueryPerformanceCounter_(@t) 
  ProcedureReturn t/maxfreq 
EndProcedure

Global Dim msg.s(5)
msg(0) = "abc"
msg(1) = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
msg(2) = Space(1000000) : FillMemory(@msg(2), 1000000, 'a', #PB_Byte) ; A string of one million "a"'s
msg(3) = "" ; Null string
msg(4) = "Test vector from febooti.com"
msg(5) = "The quick brown fox jumps over the lazy dog"

; These are the known digests for each:

Global Dim value.s(5)
value(0) = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
value(1) = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
value(2) = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"
value(3) = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
value(4) = "077b18fe29036ada4890bdec192186e10678597a67880290521df70df4bac9ab"
value(5) = "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"

Procedure progress(value)
  Static lastvalue
  If value<>lastvalue
    ; StatusBarProgress(0,0,value)
    lastvalue=value
  EndIf
EndProcedure

Procedure TestSha256(void)
  t=TicksHQ()
  For i = 0 To 5
    AddGadgetItem( 0, -1, " Test " + Str(i+1) + ":")
    digest.s = SHA256Fingerprint(@msg(i), Len(msg(i) ))
    If digest <> value(i)
      AddGadgetItem( 0, -1, "     failed!" )
    Else
      AddGadgetItem( 0, -1, "     passed." )
    EndIf
  Next 
  v=TicksHQ()
  StatusBarProgress(0,0,0)
  AddGadgetItem(0, -1, Str(v-t))
EndProcedure

OpenWindow(0,0,0,640,480,"SHA-256 Validation Tests:", #PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ListViewGadget(0,40,20,560,360)
ButtonGadget(1, 300,400,80,20,"Do the tests")
CreateStatusBar(0, WindowID(0))
AddStatusBarField(640)

Repeat
  EventID = WaitWindowEvent()
  Select EventID
    Case #PB_Event_Gadget
      If EventGadget()=1
        If Not IsThread(tid)
          StatusBarProgress(0,0,0)
          tid = CreateThread(@TestSha256(),0)
        EndIf
      EndIf
  EndSelect
  
Until EventID = #PB_Event_CloseWindow
Last edited by netmaestro on Tue Aug 30, 2011 10:26 pm, edited 31 times in total.
BERESHEIT
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

works on linux except it doesn't like test two, not sure what the problem is there.
Gets an IMA line 178
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

Test two is longer than 64 bytes, which is significant. See if you can find the problem as it works on Windows with all tests. (I don't have Linux here) Did it successfully manage test 3? (one million 'a' chars)
BERESHEIT
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

It's only working on buffers less than 64 bytes, I will have a look and see if I can fix it
if test 3 was the million chars, I had the array index '2' in my eyes
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

Yes, array index 2 is the million-char test. (zero-based array)
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

oops I found this in sha256_finish:

Code: Select all

sha256_update( *ctx, @msglen, 8, *calback )
*callback is misspelled!

fixed in the posted code.

I hate this damn keyboard... :evil: It's new and shiny and it looks really nice and I'm going to stomp it to flinders and go back to my old one that has crap and shit all over it, the badge of countless triumphs in the face of certain death :twisted: I couldn't bring myself to throw it out, now I'm glad I didn't. The hell with my wife and the horse she rode in on. (don't tell her I said that :shock: :shock: :shock: )
Last edited by netmaestro on Mon Aug 08, 2011 6:31 am, edited 1 time in total.
BERESHEIT
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

That was probably it, I just stepped through with the window and callback removed and it worked fine

just as well she doesn't read the forum :lol:
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

Please fix *callback and try all tests again, it's appreciated!
BERESHEIT
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

just as well she doesn't read the forum
No, she's into plants and art. Code talk makes her eyelids droop.
BERESHEIT
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

same as mine, suits me fine :lol:

It's still doing it, I will have a glass of wine and fix it.
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

replace the CallFunctionFast with CallCFunctionFast, amazing what a sip of wine does!
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

That kills it dead on Windows, but if it works well on Linux I can change the code to:

Code: Select all

    If *callback
      progress.f = (totalbytes-length)/totalbytes*100
      CompilerIf #PB_Compiler_OS = #PB_OS_Linux
        CallCFunctionFast(*callback, Int(progress) )
      CompilerElse
        CallFunctionFast(*callback, Int(progress) )
      CompilerEndIf
    EndIf
Should I do that? Please test on Linux and let me know.
BERESHEIT
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

probably need to do the same for linux and mac
but alas I just noticed that it printed failed for test 3 or is it supposed to?

Code: Select all

If *callback
      progress.f = (totalbytes-length)/totalbytes*100
      CompilerIf #PB_Compiler_OS = #PB_OS_Linux Or #PB_Compiler_OS = #PB_OS_MacOS
        CallCFunctionFast(*callback, Int(progress) )
      CompilerElse
        CallFunctionFast(*callback, Int(progress) )
      CompilerEndIf
    EndIf
Windows 11, Manjaro, Raspberry Pi OS
Image
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Re: HMAC SHA256 message digest

Post by netmaestro »

No, it's supposed to print "passed." for all tests. It does on Windows. (win7 x86 PB 4.60b3)

Please bracket that line with the logical or in it, just to humour me:

Code: Select all

CompilerIf (#PB_Compiler_OS = #PB_OS_Linux) Or (#PB_Compiler_OS = #PB_OS_MacOS)
BERESHEIT
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: HMAC SHA256 message digest

Post by idle »

that makes no difference to the outcome but yes it probably should be in brackets
perhaps I've butchered something here, I've coding all day and the eyes are line dancing.
I just replaced the tests with the first test and then it failed on all subsequent tests. :?
I will remove the thread and window and try it again.
Windows 11, Manjaro, Raspberry Pi OS
Image
Post Reply