Page 1 of 1

hmac_md5() and hmac_sha1() unicode and ascii

Posted: Sun Apr 19, 2015 3:12 pm
by infratec
Hi,

since a user needed it and the original stuff was not working, I implemented it from scratch.
Save it as hmac.pbi

Code: Select all

CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf


Procedure.s hmac_sha1(key$, msg$, blocksize.i=64, opad.a=$5C, ipad.a=$36)
  
  Protected.i KeyLength, x
  Protected Result$, i_key$
  Protected *key, *o_key_pad, *i_key_pad, *i, *o
  
  
  KeyLength = StringByteLength(key$, #PB_UTF8)
  If KeyLength > blocksize
    *key = AllocateMemory(KeyLength)
    If *key
      PokeS(*key, key$, -1, #PB_UTF8|#PB_String_NoZero)
      key$ = SHA1Fingerprint(*key, MemorySize(*key))
      FreeMemory(*key)
      KeyLength = StringByteLength(key$, #PB_UTF8)
      *key = AllocateMemory(KeyLength)
    EndIf
  ElseIf KeyLength < blocksize
    *key = AllocateMemory(blocksize)
  EndIf
  
  If *key
    PokeS(*key, key$, -1, #PB_UTF8|#PB_String_NoZero)
    
    *o_key_pad = AllocateMemory(blocksize, #PB_Memory_NoClear)
    If *o_key_pad
      For x = 0 To blocksize - 1
        PokeA(*o_key_pad + x, PeekA(*key + x) ! opad)
      Next x
      
      *i_key_pad = AllocateMemory(blocksize, #PB_Memory_NoClear)
      If *i_key_pad
        For x = 0 To blocksize - 1
          PokeA(*i_key_pad + x, PeekA(*key + x) ! ipad)
        Next x
        
        *i = AllocateMemory(blocksize + StringByteLength(msg$, #PB_UTF8))
        If *i
          CopyMemory(*i_key_pad, *i, blocksize)
          PokeS(*i + blocksize, msg$, -1, #PB_UTF8|#PB_String_NoZero)
          i_key$ = SHA1Fingerprint(*i, MemorySize(*i))
          FreeMemory(*i)
          
          *o = AllocateMemory(blocksize + 20)
          If *o
            CopyMemory(*o_key_pad, *o, blocksize)
            For x = 0 To 19
              PokeA(*o + blocksize + x, Val("$" + Mid(i_key$, x * 2 + 1, 2)))
            Next x
            
            Result$ = SHA1Fingerprint(*o, MemorySize(*o))
            FreeMemory(*o)
          EndIf
          
        EndIf
        FreeMemory(*i_key_pad)
      EndIf
      FreeMemory(*o_key_pad)
    EndIf
    FreeMemory(*key)
  EndIf
  
  ProcedureReturn Result$
  
EndProcedure




Procedure.s hmac_md5(key$, msg$, blocksize.i=64, opad.a=$5C, ipad.a=$36)
  
  Protected.i KeyLength, x
  Protected Result$, i_key$
  Protected *key, *o_key_pad, *i_key_pad, *i, *o
  
  
  KeyLength = StringByteLength(key$, #PB_UTF8)
  If KeyLength > blocksize
    *key = AllocateMemory(KeyLength)
    If *key
      PokeS(*key, key$, -1, #PB_UTF8|#PB_String_NoZero)
      key$ = MD5Fingerprint(*key, MemorySize(*key))
      FreeMemory(*key)
      KeyLength = StringByteLength(key$, #PB_UTF8)
      *key = AllocateMemory(KeyLength)
    EndIf
  ElseIf KeyLength < blocksize
    *key = AllocateMemory(blocksize)
  EndIf
  
  If *key
    PokeS(*key, key$, -1, #PB_UTF8|#PB_String_NoZero)
    
    *o_key_pad = AllocateMemory(blocksize, #PB_Memory_NoClear)
    If *o_key_pad
      For x = 0 To blocksize - 1
        PokeA(*o_key_pad + x, PeekA(*key + x) ! opad)
      Next x
      
      *i_key_pad = AllocateMemory(blocksize, #PB_Memory_NoClear)
      If *i_key_pad
        For x = 0 To blocksize - 1
          PokeA(*i_key_pad + x, PeekA(*key + x) ! ipad)
        Next x
        
        *i = AllocateMemory(blocksize + StringByteLength(msg$, #PB_UTF8))
        If *i
          CopyMemory(*i_key_pad, *i, blocksize)
          PokeS(*i + blocksize, msg$, -1, #PB_UTF8|#PB_String_NoZero)
          i_key$ = MD5Fingerprint(*i, MemorySize(*i))
          FreeMemory(*i)
 
          *o = AllocateMemory(blocksize + 16)
          If *o
            CopyMemory(*o_key_pad, *o, blocksize)
            For x = 0 To 15
              PokeA(*o + blocksize + x, Val("$" + Mid(i_key$, x * 2 + 1, 2)))
            Next x
            
            Result$ = MD5Fingerprint(*o, MemorySize(*o))
            FreeMemory(*o)
          EndIf
          
        EndIf
        FreeMemory(*i_key_pad)
      EndIf
      FreeMemory(*o_key_pad)
    EndIf
    FreeMemory(*key)
  EndIf
  
  ProcedureReturn Result$
  
EndProcedure




;-Demo
CompilerIf #PB_Compiler_IsMainFile
 
  Debug "Examples from: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code"
  Debug ""
  Debug "hmac_md5('', '')"
  Debug "Calculated: " + hmac_md5("", "")
  Debug "Should be : 74e6f7298a9c2d168935f58c001bad88"
  Debug ""
  Debug "hmac_sha1('', '')"
  Debug "Calculated: " + hmac_sha1("", "")
  Debug "Should be : fbdb1d1b18aa6c08324b7d64b71fb76370690e1d"
  Debug ""
  Debug "hmac_md5('key', 'The quick brown fox jumps over the lazy dog')"
  Debug "Calculated: " + hmac_md5("key", "The quick brown fox jumps over the lazy dog")
  Debug "Should be : 80070713463e7749b90c2dc24911e275"
  Debug ""
  Debug "hmac_sha1('key', 'The quick brown fox jumps over the lazy dog')"
  Debug "Calculated: " + hmac_sha1("key", "The quick brown fox jumps over the lazy dog")
  Debug "Should be : de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9"
  Debug ""
 
 
  Debug "user example:"
  Define.i x, Size
  Define accessID$, secretKey$, expires$, stringToSign$, signature$, encoded$
  Define *in, *out
 
  accessID$ = "mozscape-3030303030"
  secretKey$ = "8adea7512f787f2c98097ec526a9dac1"
  expires$ = "1429403104"
 
  stringToSign$ = accessID$ + #LF$ + expires$
 
  signature$ = hmac_sha1(secretKey$, stringToSign$)
  Debug  "HMAC_SHA1: " + signature$
 
  *in = AllocateMemory(40)
  *out = AllocateMemory(40 * 1.4)
 
  For x = 0 To 19
    PokeA(*in + x, Val("$" + Mid(signature$, x * 2 + 1, 2)))
  Next x
 
  Size = Base64Encoder(*in, 20, *out, MemorySize(*out))
  encoded$ = PeekS(*out, Size, #PB_Ascii)
  Debug "Base64 encoded: " + encoded$
 
  encoded$ = ReplaceString(encoded$,"+","%2B")
  encoded$ = ReplaceString(encoded$,"=","%3D")
  encoded$ = ReplaceString(encoded$,"/","%2F")
 
  Debug "URLEncoded: " + encoded$
 
CompilerEndIf
But I was too lazy to implement the complete checking stuff for AllocateMemory().
Also the AllocateMemory() for *i can be omitted if *i_key_pad is used for this too.

hmac_sha256 from Helle can be found here:
http://www.purebasic.fr/english/viewtop ... 7&p=358165

Bernd

Re: hmac_md5() and hmac_sha1() unicode and ascii

Posted: Mon Apr 20, 2015 7:53 am
by infratec
Added the safety checks for AllocateMemrory().

Re: hmac_md5() and hmac_sha1() unicode and ascii

Posted: Thu Apr 23, 2015 4:30 pm
by zikitrake
infratec wrote:Added the safety checks for AllocateMemrory().
Thank you. Your code saved me :D