HMAC SHA256

Just starting out? Need help? Post your questions and find answers here.
giammy
User
User
Posts: 16
Joined: Wed Aug 03, 2011 10:43 am

HMAC SHA256

Post by giammy »

I am a newbie
I need for an hmac_sha256 implementation in Purebasic

can anyone help me?

Thanks in advance!
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

Post by netmaestro »

Edit:

My original contribution here is obsolete, it's now replaced with this: http://www.purebasic.fr/english/viewtop ... 12&t=47120
Last edited by netmaestro on Sat Aug 20, 2011 5:06 pm, edited 1 time in total.
BERESHEIT
giammy
User
User
Posts: 16
Joined: Wed Aug 03, 2011 10:43 am

Re: HMAC SHA256

Post by giammy »

Tanks a lot!!

I will try to use it and you'll know!
Helle
Enthusiast
Enthusiast
Posts: 178
Joined: Wed Apr 12, 2006 7:59 pm
Location: Germany
Contact:

Re: HMAC SHA256

Post by Helle »

For tests you can use this:

Code: Select all

;- SHA256 and HMAC256, based (Pseudo-Code) on engl. Wikipedia
;- "Helle" Klaus Helbing, 06.08.2011, PB 4.51 (x86)
;- 32-Bit-Windows-Version with SSE2
;- Parts of Buffer: 0-7=Length.q, 8-11=Chunks.l, 12-15=MemAv, 16-51=p_a_h_A, 64-95=pHashA, 96-351=pWa, 352-355=ppAllBlocksA, 356-?=pAllBlocksA

Procedure Padding(BufferA)
  ;Size wird auf Vielfaches von 512 Bit (64 Byte) gebracht (Blocklänge ist 512 Bit)
  !mov eax,[p.v_BufferA]

  !push ebx
  !push edi  
  !push esi

  !mov ebx,eax

  !mov edi,[ebx+352]
  !add edi,ebx

  !mov eax,[ebx+12]          ;MemAv
  !mov esi,eax

  !mov ecx,64                ;512 Bit
  !xor edx,edx               ;hier mal so (ist ja unsigned)
  !div ecx                   ;Modulo steht in edx

  !inc eax                   ;eine Runde wollen wir ja wenigstens! 
  !mov [ebx+8],eax           ;Chunks
  !mov eax,[ebx+12]          ;MemAv
  !mov byte[edi+eax],80h     ;1 gesetztes Bit anhängen
  !or edx,edx                ;edx=0?
  ;1.Fall: EDX=0. Letzter 512-Bit-Block ist Vielfaches von 512 Bit (64 Byte). Es wird ein kompletter 512-Bit-Block angehängt   
  !jz @f 
  ;2.Fall: EDX<56. Letzter 512-Bit-Block ist kleiner als 448 Bit (56 Byte), aber größer Null
  !sub esi,edx
  !cmp edx,56                ;448 Bit
  !jb @f
  ;3.Fall: EDX>=56. Letzter 512-Bit-Block ist größer/gleich als 448 Bit (56 Byte). Dieser Block wird aufgefüllt (Bitwert 1 drangehängt,
  ; Rest Null) und ein weiterer Block drangehängt mit Nullen und am Ende Original-Länge als 64-Bit-Big-Endian-Wert
  !add edi,64
  !add dword[ebx+8],1        ;Chunks, es wurde ja ein Block drangehängt
!@@:  
  !add edi,esi

  !mov edx,8
  !mov eax,[ebx]             ;Size, ist Quad!
  !mul edx                   ;nicht SHL bei großen Dateien
  !mov ecx,eax
  !mov esi,edx

  !mov edx,8                 ;"Kaskadierung" für größere Dateien 
  !mov eax,[ebx+4]           ;Size, ist Quad!
  !mul edx         

  !add eax,esi               ;reicht so für heutige Festplatten/Filelängen

  !bswap ecx
  !bswap eax
  !mov [edi+56],eax          ;Original-Länge als 64-Bit-Big-Endian-Wert anhängen
  !mov [edi+60],ecx 
  
  !pop esi   
  !pop edi
  !pop ebx
EndProcedure 

Procedure Main(BufferA)
  !mov eax,[p.v_BufferA]

  !push ebp
  !push ebx
  !push edi  
  !push esi

  !mov ebp,eax

  ;W[0] bis W[15]
  !mov esi,[eax+352]
  !add esi,eax
  !mov edi,eax
  !add edi,96
  !mov ecx,8
!@@:
  !mov eax,[esi]
  !mov edx,[esi+4]
  !bswap eax
  !bswap edx
  !mov [edi],eax 
  !mov [edi+4],edx
  !add edi,8
  !add esi,8
  !dec ecx
  !jnz @b
  ;W[16] bis W[63]
  !mov ecx,48
  !mov esi,ebp
  !add esi,96+64
!@@:
  ;s0
  !mov eax,dword[esi-60]
  !mov edx,eax
  !mov edi,eax
  !ror eax,7
  !ror edx,18 
  !shr edi,3
  !xor eax,edx
  !xor edi,eax
  ;s1
  !mov eax,dword[esi-8]
  !mov edx,eax
  !mov ebx,eax
  !ror eax,17
  !ror edx,19
  !xor eax,edx
  !shr ebx,10
  !xor eax,ebx
  ;W[i]
  !mov edx,dword[esi-64]
  !add edx,edi               ;edi=s0
  !add edx,dword[esi-28]
  !add edx,eax               ;eax=s1
  !mov dword[esi],edx
  !add esi,4
  !dec ecx
  !jnz @b
  ;Initialisierung
  !mov esi,ebp               ;[p.v_BufferA]
  !add esi,16                ;p_a_h_A
  !mov eax,ebp
  !add eax,64
  !movdqa xmm0,[eax]
  !movdqa xmm1,[eax+16]
  !movdqa [esi],xmm0
  !movdqa [esi+16],xmm1
  ;Main Loop
  !xor ecx,ecx               ;hier mal so
!@@:
  ;s0
  !mov eax,[esi]
  !mov edx,eax
  !mov edi,eax
  !ror eax,2
  !ror edx,13
  !xor eax,edx
  !ror edi,22
  !xor edi,eax               ;edi=s0
  ;maj (major)               maj = (a and b) + (c and (a xor b))
  !mov eax,[esi]             ;a
  !mov edx,eax
  !mov ebx,[esi+4]            ;b
  !xor eax,ebx               ;(a xor b)
  !and ebx,edx               ;(a and b)
  !and eax,[esi+8]           ;c
  !add ebx,eax               ;ebx=maj
  ;t2
  !add ebx,edi               ;ebx=t2, edi=s0
  ;s1
  !mov eax,[esi+16]
  !mov edx,eax
  !mov edi,eax
  !ror eax,6
  !ror edx,11
  !xor eax,edx
  !ror edi,25
  !xor edi,eax               ;edi=s1
  ;ch                         ch = g xor (e and (f xor g))
  !mov eax,[esi+24]          ;g
  !mov edx,eax
  !xor edx,[esi+20]          ;f
  !and edx,[esi+16]          ;e
  !xor edx,eax
  ;t1
  !mov eax,[esi+28]
  !add eax,edi               ;s1
  !add eax,edx               ;ch
  !lea edi,[k_256]           ;Data
  !add eax,dword[edi+ecx]    ;k[i]
  !mov edi,ebp
  !add edi,96
  !add eax,dword[edi+ecx]    ;eax=t1, edi+ecx=W[i]
  ;Vertauschungen
  !mov edx,[esi+12]          ;"altes" d
  !add edx,eax               ;eax=t1
  !movdqa xmm0,[esi]
  !movdqa xmm1,[esi+16]
  !movdqu [esi+4],xmm0       ;mit Versatz von 4 Bytes zurückkopieren 
  !movdqu [esi+20],xmm1
  !add eax,ebx               ;eax=t1, ebx=t2
  !mov [esi],eax             ;"neues" a
  !mov [esi+16],edx          ;"neues" e 

  !add ecx,4
  !cmp ecx,256
  !jb @b
  ;am Ende jedes Chunks Hashs zu vorhandenen Werten aufaddieren (Überträge werden ignoriert!)
  !mov edi,ebp
  !add edi,64
  !movdqa xmm0,[edi]
  !paddd xmm0,[esi]
  !movdqa [edi],xmm0
  !movdqa xmm0,[edi+16]
  !paddd xmm0,[esi+16]
  !movdqa [edi+16],xmm0

  !mov eax,ebp
  !add dword[eax+352],64     ;512 Bit (64 Byte) weiter, nächster Chunk
   
  !pop esi
  !pop edi
  !pop ebx
  !pop ebp
EndProcedure   

Procedure.s SHA256Fingerprint_32(*Source, Length)
  SizeAv = Length

  If Length > $40000 
    MemAv = $40000
    LCopy = $40000
    Chunks = $1000
    ChunksOld = Chunks
   Else
    MemAv = Length
    LCopy = Length
  EndIf

  Buffer = AllocateMemory(356 + MemAv + 128)
  i = Buffer % 16
  If i 
    BufferA = Buffer - i + 16          ;Alignment 16
   Else
    BufferA = Buffer
  EndIf

  CopyMemory(?HashBase_256, BufferA + 64, 32)    ;to pHashA

  PokeQ(BufferA, Length)

  pAllBlocksStart = 356
  PokeL(BufferA + 352, pAllBlocksStart)     ;Pointer in pAllBlocksA

  If Length = 0
    PokeL(BufferA + 12, MemAv)
    Padding(BufferA)
    Chunks = PeekL(BufferA + 8)
    Main(BufferA)
  EndIf  
  
  While SizeAv

    CopyMemory(*Source + Seek, BufferA + pAllBlocksStart, LCopy) ;to pAllBlocksA

    BytesCopy = LCopy
    Seek + BytesCopy
    SizeAv - BytesCopy
    
    If SizeAv < LCopy    
      LCopy = SizeAv  
    EndIf  
    
    If SizeAv = 0 
      PokeL(BufferA + 12, MemAv)
      Padding(BufferA)  
      Chunks = PeekL(BufferA + 8)
    EndIf

    While Chunks                       ;512 Bit (64 Byte)
      Main(BufferA)
      Chunks - 1
    Wend

    PokeL(BufferA + 352, pAllBlocksStart)

    If SizeAv <= MemAv 
      MemAv = SizeAv
      NewMem = MemAv + 128
      For i = 0 To NewMem
        PokeB(BufferA + 356 + i, 0)
      Next
     Else
      Chunks = ChunksOld
    EndIf

  Wend 

  SHA256$ = ""
  For i = 0 To 28 Step 4
    SHA256$ + RSet(Hex(PeekL(BufferA + 64 + i) & $FFFFFFFF), 8, "0")
  Next

  FreeMemory(Buffer)

 ProcedureReturn SHA256$

DataSection   ;Read only, evtl. ohne
HashBase_256: ;The first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19, Big-Endian!
  Data.l $6a09e667, $bb67ae85, $3c6ef372, $a54ff53a, $510e527f, $9b05688c, $1f83d9ab, $5be0cd19
!k_256:       ;The first 32 bits of the fractional parts of the cube roots of the first 64 primes 2...311, Big-Endian!
  Data.l $428a2f98, $71374491, $b5c0fbcf, $e9b5dba5, $3956c25b, $59f111f1, $923f82a4, $ab1c5ed5
  Data.l $d807aa98, $12835b01, $243185be, $550c7dc3, $72be5d74, $80deb1fe, $9bdc06a7, $c19bf174
  Data.l $e49b69c1, $efbe4786, $0fc19dc6, $240ca1cc, $2de92c6f, $4a7484aa, $5cb0a9dc, $76f988da
  Data.l $983e5152, $a831c66d, $b00327c8, $bf597fc7, $c6e00bf3, $d5a79147, $06ca6351, $14292967
  Data.l $27b70a85, $2e1b2138, $4d2c6dfc, $53380d13, $650a7354, $766a0abb, $81c2c92e, $92722c85
  Data.l $a2bfe8a1, $a81a664b, $c24b8b70, $c76c51a3, $d192e819, $d6990624, $f40e3585, $106aa070
  Data.l $19a4c116, $1e376c08, $2748774c, $34b0bcb5, $391c0cb3, $4ed8aa4a, $5b9cca4f, $682e6ff3
  Data.l $748f82ee, $78a5636f, $84c87814, $8cc70208, $90befffa, $a4506ceb, $bef9a3f7, $c67178f2
EndDataSection
EndProcedure

Goto No_SHA256_Test
;SHA256-Test
Test256$ = "The quick brown fox jumps over the lazy dog"   ;D7A8FBB307D7809469CA9ABCB0082E4F8D5651E46D3CDB762D02D0BF37C9E592
SHA256$ = SHA256Fingerprint_32(@Test256$, StringByteLength(Test256$))
MessageRequester("SHA256 Fingerprint", SHA256$)

Test256$ = "The quick brown fox jumps over the lazy dog."  ;EF537F25C895BFA782526529A9B63D97AA631564D5D789C2B765448C8635FB6C
SHA256$ = SHA256Fingerprint_32(@Test256$, StringByteLength(Test256$))
MessageRequester("SHA256 Fingerprint", SHA256$)
No_SHA256_Test:

;- HMAC
Procedure Key_XOR(Buffer, Source)
  !mov eax,[p.v_Source]
  !movdqu xmm0,[eax]
  !mov ecx,4
  !mov edx,[p.v_Buffer]
!@@:  
  !movdqu xmm1,[edx]
  !pxor xmm1,xmm0
  !movdqu [edx],xmm1
  !add edx,16
  !dec ecx
  !jnz @b
EndProcedure

Procedure Concatenation(Buffer, Hash)
  !mov eax,[p.v_Hash]
  !mov edx,[p.v_Buffer]
  !mov ecx,8
  !push ebx
!@@:  
  !mov ebx,[eax]
  !bswap ebx
  !mov [edx],ebx
  !add eax,4
  !add edx,4
  !dec ecx
  !jne @b
  !pop ebx
EndProcedure

Procedure.s HMAC256_32(*Source, LengthSource, *Key, LengthKey)
  ;For this test LengthKey <= 64 bytes
  pMem = AllocateMemory(64 + LengthSource)

  CopyMemory(*Key, pMem, LengthKey)

  ;Key XOR ipad
  Key_XOR(pMem, ?ipad)       ;$36

  CopyMemory(*Source, pMem + 64, LengthSource)

  Hash1$ = SHA256Fingerprint_32(pMem, LengthSource + 64)
  FreeMemory(pMem)

  pMem = AllocateMemory(96)

  CopyMemory(*Key, pMem, LengthKey)

  ;Key XOR opad
  Key_XOR(pMem, ?opad)       ;$5C

  Hash1 = AllocateMemory(32)
  ;Hash1$ wieder zurück in Bytes
  For i = 0 To 28 Step 4
    PokeL(Hash1 + i, Val("$" + Mid(Hash1$, (i*2)+1, 8)) & $FFFFFFFF) 
  Next

  Concatenation(pMem + 64, Hash1)

  FreeMemory(Hash1)

  HMAC$ = SHA256Fingerprint_32(pMem, 96)

  FreeMemory(pMem)

 ProcedureReturn HMAC$

DataSection
ipad:
  Data.q $3636363636363636, $3636363636363636
opad:
  Data.q $5c5c5c5c5c5c5c5c, $5c5c5c5c5c5c5c5c  
EndDataSection
EndProcedure

;HMAC256-Test   for this test Key <= 64 bytes 
Test256$ = "The quick brown fox jumps over the lazy dog"   ;45B777B61761A73762CA620A2F9FAD388117A89C59DEA32D9AE207827E26C174
Key$ = "Yappadappadu"
HMAC256$ = HMAC256_32(@Test256$, StringByteLength(Test256$), @Key$, StringByteLength(Key$))
MessageRequester("HMAC256_32", HMAC256$)
For very old CPUs you can replace the SSE2-parts.

Have fun!
Helle
giammy
User
User
Posts: 16
Joined: Wed Aug 03, 2011 10:43 am

Re: HMAC SHA256

Post by giammy »

thanks a lot!
Post Reply