Page 1 of 2

MD5FingerprintBin()

Posted: Fri Aug 12, 2005 7:30 pm
by Rescator
Why? Because this code is so ugly, but sadly something I use a lot on some programs!

A function similar to this one, is what I'd love to see. PHP5 has it for MD5 and SHA too I believe.

The other benefit is that binary should be much faster right? (or does the md5 implementation actually do it as hex internally?)

Code: Select all

EnableExplicit

Procedure.l MD5FingerprintBin(*buf,len.i,*md5bin) ;returns a pointer to a 16 byte md5 binary fingerprint
 Protected hex.s, x.i, a.i, b.i, c.i, i.i
 hex.s=UCase(MD5Fingerprint(*buf,len))
 i=0
 For x=0 To 31 Step 2
  a=PeekB((@hex)+x) & $FF
  If a<58
   a=a-48
  Else
   a=a-55
  EndIf
  b=PeekB((@hex)+(x+1)) & $FF
  If b<58
   b=b-48
  Else
   b=b-55
  EndIf
  PokeB(*md5bin+i,(a<<4)+b)
  i+1
 Next
 ProcedureReturn *md5bin
EndProcedure


Define *md5bin,text$
*md5bin=AllocateMemory(16)

text$="Test!"
MD5FingerprintBin(@text$,StringByteLength(text$),*md5bin) ;returns a pointer to *md5bin or 0 if error.

Posted: Thu May 14, 2009 2:34 am
by Rescator
As I know Fred hates bumps, I took this opportunity to update/change the example to something better. (the old example was unsafe in multi-threaded uses etc.)

@PB Team: If you folks don't wanna do this one, then could you point me to the md5 source you based this on so that I can get similar behavior/speed for a bin variant as the native hex one has?

For those wondering why I need a bin variant, beyond possibly speed improvement (no string/hex handling overhead etc.)...
When building a combined key using MD5 hashes, I can for example get twice as many md5 hashes into 1024 bytes if the hashes are binary as opposed to hex (2 bytes for 1 character) which would be just 2*512 and half the potential strength.

PHP5's bin support: http://no.php.net/manual/en/function.md5.php

Posted: Thu May 14, 2009 10:29 am
by Fred
The MD5 is indeeded calculated in binary format, only the result is transformed into string, so it will have absolutely no speed gain to do a 'bin' function. BTW, your procedure code can be made somewhat easier:

Code: Select all

Procedure.l MD5FingerprintBin(*buf,len.i,*md5bin) ;returns a pointer to a 16 byte md5 binary fingerprint
 Protected hex.s, x.i
 hex.s = MD5Fingerprint(*buf, len)

 For x=0 To 31 Step 2
  PokeB(*md5bin+x/2, Val("$"+Mid(hex, x+1, 2)))
 Next

 ProcedureReturn *md5bin
EndProcedure

Posted: Thu May 14, 2009 1:43 pm
by DoubleDutch
PokeB(*md5bin+x/2, Val("$"+Mid(hex, x+1, 2)))
Nice trick to convert back from hex. I'll pinch that.

Posted: Thu May 14, 2009 10:00 pm
by Rescator
Fred wrote:The MD5 is indeeded calculated in binary format, only the result is transformed into string, so it will have absolutely no speed gain to do a 'bin' function.
Yeah but exposing the non-transformed (raw as PHP calls it) result would actually speed things up for situations like this:

(concept only)
Define *md5bin,text$
*md5bin=AllocateMemory(256)

text$="This is a test, a long line of text! Like a passphrase!"
MD5FingerprintBin(@text$,Len(text$),*md5bin)
MD5FingerprintBin(@text$+1,Len(text$)-1,*md5bin+16)
MD5FingerprintBin(@text$+2,Len(text$)-2,*md5bin+32)
MD5FingerprintBin(@text$+3,Len(text$)-3,*md5bin+48)
MD5FingerprintBin(@text$+4,Len(text$)-4,*md5bin+64)

Luckily one would not need to build a key like this that often,
but it still feels silly that something that originally is a binary md5 is turned to hex, then turned to binary again. A raw or Bin variant would avoid the hex stuff fully.

Maybe I'm just nitpicking but... :P

Oh and thanks for the hex/bin tip there, never thought of that one before :)

Re: MD5FingerprintBin()

Posted: Mon Feb 10, 2020 9:09 am
by Rinzwind
Late to the party. You're not nitpicking. The fingerprint functions seem to follow some kind of backwards thinking. One should start with a PB build-in function that gives as result a byte pointer and after that add convenience functions that translate a byte pointer into a string hex representation. And to be complete, a function that transforms a string hex into a byte pointer. Right?

As of now, we need things like (viewtopic.php?t=63309) which should not be necessary.

Code: Select all

  Global Dim HexTable.a(127)
  Procedure InitHexTable()
    Protected i
    For i = '0' To '9'
      HexTable(i) = (i -'0')
    Next
    For i = 'a' To 'f'
      HexTable(i) = (i -'a' + 10)
    Next
    For i = 'A' To 'F'
      HexTable(i) = (i -'A' + 10)
    Next
    For i = 0 To 15
      HexTable(i) = Asc(Hex(i))
    Next
  EndProcedure
  
  Structure DoubleChar
    c1.c
    c2.c
  EndStructure
  
  Procedure.s MemToHex(*mem.ascii, memlen)
    Protected *pos.DoubleChar
    Protected shex.s
    shex = Space(memlen * 2)
    *pos = @shex
    While memlen > 0
      *pos\c1 = HexTable(*mem\a >> 4)
      *pos\c2 = HexTable(*mem\a & $f)
      *pos +SizeOf(DoubleChar)
      *mem +1
      memlen -1
    Wend
    ProcedureReturn shex
  EndProcedure
  
  Procedure HexToMem(*phex.DoubleChar, *mem=0, memlen=0)
    Protected *pos.ascii
    Protected hexlen
    hexlen = MemoryStringLength(*phex)
    If hexlen & %1
      ProcedureReturn 0
    EndIf
    If *mem = 0
      memlen = hexlen / 2
      *mem = AllocateMemory(memlen)     
    ElseIf memlen=0
      memlen = MemorySize(*mem)
    EndIf
    If memlen >= hexlen/2
      *pos = *mem
      While *phex\c1 > 0 And *phex\c2 > 0
        *pos\a = HexTable(*phex\c1 & $7f) << 4 + HexTable(*phex\c2 & $7f)
        *phex +SizeOf(DoubleChar)
        *pos +1
      Wend
      ProcedureReturn *mem
    EndIf
    ProcedureReturn 0   
  EndProcedure
  
  Procedure.s HexToStr(*hex.DoubleChar)
    Protected str.s, len
    len = MemoryStringLength(*hex) / SizeOf(character) / 2
    str = Space(len)
    HexToMem(*hex, @str, StringByteLength(str))
    ProcedureReturn str
  EndProcedure  

Re: MD5FingerprintBin()

Posted: Tue May 11, 2021 3:27 pm
by Controller
I would also appreciate an MD5FingerprintBin() function...

Re: MD5FingerprintBin()

Posted: Sun May 23, 2021 8:34 am
by Saki
You can emulate that.
It is then no longer an md5 hash, but a hash based on md5.
Probably the collision safety is even higher thereby, as a significant diffusion is added.
And it is very fast.

Practically this construction is applicable for example with the blockwise transfer of files.
The individual hashes then always add up automatically to a new one for each block,
without further intervention.

Since the Pre Image is, a md5 is also absolutely OK.

The problem is that it is hard to sell to a person who doesn't understand it.
If he asks which hash method is used and you say an md5 based one,
a lot of people probably start hyperventilating, because they think they know something very clever,
that md5 is broken.
Which is absolute cheese in this context.

It's probably not that easy to understand how this works.

Code: Select all

Define text$="Hello i am a md5 based 16 byte binary hash"
Define *source=@text$
Define *hash_buffer=AllocateMemory(16)

Procedure BinHash16(*source, source_length, *hash_buffer)
  UseMD5Fingerprint() ; By Saki
  Define md5$=Fingerprint(*source, source_length, #PB_Cipher_MD5)
  FillMemory(*hash_buffer, 16, 0)
  AESEncoder(*hash_buffer, *hash_buffer, 16, @md5$, 256, 0, #PB_Cipher_ECB)
EndProcedure

BinHash16(@text$, StringByteLength(text$), *hash_buffer)
ShowMemoryViewer(*hash_buffer, 16) ; Binary md5 based hash

Re: MD5FingerprintBin()

Posted: Sun May 23, 2021 10:16 am
by Mijikai
On Windows OS the Crypt API could be a option (CryptAcquireContextW -> CryptGetHashParam).
The API is pretty neat as it supports most hashes, i used it before but i also wrote a routine that generates a hex string.
Anyway there is (almost) no speed benefit when not converting the result to a string so i dont see the problem tbh.
The PB functions works just fine and i suggest to use it unless u have a solid reason not to.

Re: MD5FingerprintBin()

Posted: Sun May 23, 2021 11:15 am
by GPI
I wrote a faster "dehex"-routine, run the example with disabled debugger for valid results.

Code: Select all

UseMD5Fingerprint()

Procedure DeHex(*str.character,*result.ascii)
  Protected.l flip
  Protected.A val,hiByte
  While *str\c >0
    val = *str\c - '0'
    If val > 9
      val - ('A'-'0'-10)
      If val > 15
        val - ('a'-'A')
        If val > 15
          Break 
        EndIf
      EndIf
    EndIf
    Debug val
    If flip
      *result\a = (hiByte << 4) | val
      ;Debug ">>" + *result\a+" " + Str(hiByte<<8)+" "+val
      *result + SizeOf(ascii)
      flip=#False
    Else
      hiByte = val
      flip=#True
    EndIf
    *str+SizeOf(Character)
  Wend
  ProcedureReturn *result
EndProcedure
Procedure.s ToHex(*dat.ascii, len)
  Protected.l i
  Protected.s str=""
  For i=1 To len
    str+Right("0"+Hex(*dat\a),2)
    *dat + SizeOf(ascii)
  Next
  ProcedureReturn str
EndProcedure



str.s = UCase(StringFingerprint("Something",#PB_Cipher_MD5))
  buflen = (Len(str)+1)/2
  *dest1 = AllocateMemory(buflen)
  
  
timer= ElapsedMilliseconds()
For i=0 To 1000000
  DeHex(@str, *dest1)
Next
timer = ElapsedMilliseconds()-timer

*dest2 = AllocateMemory(buflen)
  
timer2= ElapsedMilliseconds()
For i=0 To 1000000

 For x=0 To 31 Step 2
   PokeB(*dest2+x/2, Val("$"+Mid(str, x+1, 2)))
  Next
  
  Next
timer2 = ElapsedMilliseconds()-timer2



MessageRequester("test","md5  :"+str +#LF$ +
                        "deHex:"+ tohex(*dest1,buflen)+" "+timer+"ms"+#LF$ +
                        "val  :"+ tohex(*dest2,buflen)+" "+timer2+"ms"+#LF$+
                        "")

Re: MD5FingerprintBin()

Posted: Sun May 23, 2021 11:23 am
by Keya
A hash in hex format is only useful for display purposes ... whereas, for processing and storage it's better in it's original binary format. It should be up to the programmer to convert a binary hash to hex ... it's frustrating at the moment that we have to decode a hexadecimal hash to recover the binary version (bin -> hex -> bin), especially as it would require less code, and especially as the code to do so already exists within PB but isn't available. This is why I don't use the Fingerprint() functions.

Re: MD5FingerprintBin()

Posted: Sun May 23, 2021 11:32 am
by Saki
Well, my function above is hard to figure out, but it also doesn't require NextFingerprint() and is extremely fast.

It doesn't get any simpler or more efficient in the PB environment, I think.

A similar solution can be created for all hashes.

Re: MD5FingerprintBin()

Posted: Sun May 23, 2021 3:13 pm
by Mijikai
I posted some hashing code for Windows (Hash to Bin).
The code supports several hashing algorithms.
This time i used the newest Crypto API (BCrypt).

Code:
https://www.purebasic.fr/english/viewto ... 05#p570605

Have fun 8)

Re: MD5FingerprintBin()

Posted: Mon Nov 15, 2021 4:29 am
by Rinzwind
Here we are again. Still no changes. Had to change PB's hex string to bin again lately... which PB does not even support a function for, which would be the least to offer when it chooses hex strings as results. Can this lib get some attention please? Add some other common used algorithms like HMAC while your at it. Then again, listening to and taking advise from the community is not a thing with PB.

Re: MD5FingerprintBin()

Posted: Mon Nov 15, 2021 7:03 am
by BarryG
Rinzwind wrote: Mon Nov 15, 2021 4:29 amlistening to and taking advise from the community is not a thing with PB.
It used to be, years ago. Fred was extremely active here. Kinda makes me sad that he doesn't anymore. Even the Blog doesn't get the love that it used to. I know times change and the language is going through a LOT of work at the moment, though. But even a weekly Blog update about what's currently going on would be good. Customers need that interaction.