News:

Help! We're trapped in the computer, and the computer is trapped in 2008! Someone call the time police!

Main Menu

[VB6] AHM! (Another Hashing Method)

Started by Joe, August 17, 2005, 09:41:11 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Joe

I wrote another hashing method, and this time its rather decent, IMO. Comment, if thou dare! =)


Option Explicit

Private Const Alphabet = "3412785609PLMZAQWSXMKONJIEDCVFRBUHTFCVGY"

Public Function Hash(S As String) As String
    Dim Ret As String, Ret2 As String, i As Byte, V1 As Byte, V2 As Byte
   
P1: For i = 1 To Len(S)
        Let V1 = Asc(Mid(S, i, 1)) Mod 34
        Let V2 = Int(Asc(Mid(S, i, 1)) / 34)
        Let Ret = Ret & Chr((V1 + V2) Mod 128)
    Next i
   
P2: For i = 1 To Len(Ret) Step 2
        If Len(Ret) < i + 1 Then GoTo P3
        Let V1 = Asc(Mid(Ret, i, 1))
        Let V2 = Asc(Mid(Ret, i + 1, 1))
        Ret2 = Ret2 & Chr(V1 + V2)
    Next i
   
P3: Let Ret = Ret2: Let Ret2 = vbNullString
    For i = 1 To Len(Ret)
        Let V1 = Asc(Mid(S, i, 1)) Mod 34
        Let V2 = Int(Asc(Mid(S, i, 1)) / 34)
        Let Ret2 = Ret2 & Chr(V1) & Chr(V2)
    Next i
   
    Let Hash = MakeReadable(Pad(Ret2))
End Function

Private Function Pad(S As String) As String
    Randomize: Dim i As Byte, Padding As String
   
    For i = 1 To 128
        Let Padding = Padding & Chr(i + 127)
    Next i
   
    Let Pad = Left(S & Padding, 128)
End Function

Private Function MakeReadable(Data As String) As String
    Dim Ret As String, i As Integer
    For i = 1 To Len(Data)
        Let Ret = Ret & Mid(Alphabet, Val(Asc(Mid(Data, i, 1)) Mod Len(Alphabet)) + 1, 1)
    Next i
    Let MakeReadable = Ret
End Function



Hash("joetheodd")
0000:  37 32 39 32 48 31 41 32 30 39 50 4C 4D 5A 41 51   7292H1A209PLMZAQ
0010:  57 53 58 4D 4B 4F 4E 4A 49 45 44 43 56 46 52 42   WSXMKONJIEDCVFRB
0020:  55 48 54 46 43 56 47 59 33 34 31 32 37 38 35 36   UHTFCVGY34127856
0030:  30 39 50 4C 4D 5A 41 51 57 53 58 4D 4B 4F 4E 4A   09PLMZAQWSXMKONJ
0040:  49 45 44 43 56 46 52 42 55 48 54 46 43 56 47 59   IEDCVFRBUHTFCVGY
0050:  33 34 31 32 37 38 35 36 30 39 50 4C 4D 5A 41 51   3412785609PLMZAQ
0060:  57 53 58 4D 4B 4F 4E 4A 49 45 44 43 56 46 52 42   WSXMKONJIEDCVFRB
0070:  55 48 54 46 43 56 47 59 33 34 31 32 37 38 35 36   UHTFCVGY34127856


EDIT -
And if you want to send this over a network, you can hash to DWORD[32]. I suppose inserting the normal hash as a Non-NTString works too, but thats beside the point. =)
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal numBytes As Long)

Public Function HashAsDWORD(S As String) As Long()
    Dim Hashed As String: Let Hashed = Hash(S)
    Dim Ret(32) As Long
   
    For i = 1 To 128 Step 4
        Ret(i) = GetDWORD(Mid(Hashed, i, 4))
    Next i
   
    Let HashAsDWORD = Ret
End Function

Public Function GetDWORD(Data As String) As Long
    Dim lReturn As Long
    Call CopyMemory(lReturn, ByVal Data, 4)
    GetDWORD = lReturn
End Function
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


iago

#1
www.javaop.com/~iago/joehash.bas

To summarize, working backwards:
- MakeReadable does nothing secure.  All characters will be less than 34, and the "Language" is longer than 34.
- Pad does nothing.  Since the characters are sequential, it's easy to eliminate

- P3 and P1 are full of collisions, which is a weakness.  And any output character can be narrowed down to 2 characters.  That's easily bruteforced, since it'll take len(fullstring) ** 4 guesses, which isn't terribly high unless you're hashing huge amounts of data.  Even then, you could probably do some statistical checking. 
- P2 is also full of collisions.  Besides that, it does nothing but sum every pair of characters.  That can be again narrowed down to a polynomial number of guesses. 

Better than your last one, though :-P

(No, I'm not going to write a proof-of-concept dehasher or hash-cloner)

Joe

#2
Eh, I terminated it at 16 characters and made my brother a password for MSN by hashing his name. MSN rated it a "medium" security password.

EDIT -
MakeReadable() was meant to make it plain text, as it would spit out some nice, non-plain-text results. It wasn't meant to randomize it any.
Pad() was meant to pad it, not randomize it. That way all the results are the same length, and can be, for example, inserted in a DWORD[32] array instead of specifing the length of the array.
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


iago

Quote from: Joex86] link=topic=2336.msg22133#msg22133 date=1124394599]
Eh, I terminated it at 16 characters and made my brother a password for MSN by hashing his name. MSN rated it a "medium" security password.

EDIT -
MakeReadable() was meant to make it plain text, as it would spit out some nice, non-plain-text results. It wasn't meant to randomize it any.
Pad() was meant to pad it, not randomize it. That way all the results are the same length, and can be, for example, inserted in a DWORD[32] array instead of specifing the length of the array.

Then why use a weird character string?  Why not map them to ABC..Z?

And why not pad it with "0"'s, after it's completed?  Or why not pad with values before starting? 

Joe

QuoteThen why use a weird character string?  Why not map them to ABC..Z?
Because the way I pad it, the padding would be ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCD etc. This way, looks semi-random at first sight, so you can't find the length of the original string without at least a bit of effort.

QuoteAnd why not pad it with "0"'s, after it's completed?
Again, the hashed string (before padding) is the same length as the original string (I think?) so padding it with 0's makes the original length rather obvious.

QuoteOr why not pad with values before starting?
I'd have to cast it to Byte[128] instead of a string. No real disadvantage, but that'd be annoying.
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


iago

Also, what happens if they put a string of 1000 characters? The returned string would be 1000 characters, and wouldn't fit into your pretty little 128-byte paradigm? :P

Joe

Pad() would terminate it at 128 bytes. =)
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


iago

But what if the original string is too long?  Pad() wouldn't add anything, but your new string would still be longer than 128!

Joe

VisualBasic uses unicode C-Style strings, so it won't be terminated until it gets to a null terminator. Also, a Chr(0) won't be recongnized as a NT, for some reason I don't understand. Hence, there is no maximum length string. If you were to pass a string more longer than the ammount of RAM you have, however, you simply need to get a hobby.
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


MyndFyre

Quote from: Joex86] link=topic=2336.msg22338#msg22338 date=1124493110]
VisualBasic uses unicode C-Style strings, so it won't be terminated until it gets to a null terminator. Also, a Chr(0) won't be recongnized as a NT, for some reason I don't understand. Hence, there is no maximum length string. If you were to pass a string more longer than the ammount of RAM you have, however, you simply need to get a hobby.

You can easily pass a string beyond the amount of RAM you have; that is why Windows uses Virtual Memory (I thought that you were into OS development, Joe).
Quote from: Joe on January 23, 2011, 11:47:54 PM
I have a programming folder, and I have nothing of value there

Running with Code has a new home!

Quote from: Rule on May 26, 2009, 02:02:12 PMOur species really annoys me.

Joe

Well, it would need to be loaded in physical ram to be used, wouldn't it? I suppose you could push the beginning to VRAM and load the ending, but thats a little nutty. Alright, the least memory any computer still in (everyday) use is 64MB, agree? Are you really going to waste your day generating and passing a 64MB string? Power users have 512MB or more of RAM, which would be even more silly.
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


MyndFyre

It wouldn't be too bad.  I've memory-mapped a file to fill up my hard drive (so that I could fill up the space so I could defrag it better).  I could quickly generate a full 16gb file in under a minute, writing 0s to it the entire file.
Quote from: Joe on January 23, 2011, 11:47:54 PM
I have a programming folder, and I have nothing of value there

Running with Code has a new home!

Quote from: Rule on May 26, 2009, 02:02:12 PMOur species really annoys me.

Joe

Come to think about it, thats a great idea! =)
Quote from: Camel on June 09, 2009, 04:12:23 PMI'd personally do as Joe suggests

Quote from: AntiVirus on October 19, 2010, 02:36:52 PM
You might be right about that, Joe.


iago

Quote from: Joex86] link=topic=2336.msg22338#msg22338 date=1124493110]
VisualBasic uses unicode C-Style strings, so it won't be terminated until it gets to a null terminator. Also, a Chr(0) won't be recongnized as a NT, for some reason I don't understand. Hence, there is no maximum length string. If you were to pass a string more longer than the ammount of RAM you have, however, you simply need to get a hobby.

No, VB doesn't use C-Style strings.  VB-strings are prepended with the length, then the string itself with no terminator.  Something like:
"26abcdefghijklmnopqrstuvwxyz" for the string "abcdefghijklmnopqrstuvwxyz". 

And the point was, the reason you said you padded it was "Pad() was meant to pad it, not randomize it. That way all the results are the same length, and can be, for example, inserted in a DWORD[32] array instead of specifing the length of the array".  However, if the string you're attempting to hash is overly long, it's not going to fit into a 128-byte structure.  What that means is that it will probably get truncated, causing a whole mess of collision-issues with long strings. 

MyndFyre

Quote from: iago on August 20, 2005, 02:22:53 PM
Quote from: Joex86] link=topic=2336.msg22338#msg22338 date=1124493110]
VisualBasic uses unicode C-Style strings, so it won't be terminated until it gets to a null terminator. Also, a Chr(0) won't be recongnized as a NT, for some reason I don't understand. Hence, there is no maximum length string. If you were to pass a string more longer than the ammount of RAM you have, however, you simply need to get a hobby.

No, VB doesn't use C-Style strings.  VB-strings are prepended with the length, then the string itself with no terminator.  Something like:
"26abcdefghijklmnopqrstuvwxyz" for the string "abcdefghijklmnopqrstuvwxyz". 

And the point was, the reason you said you padded it was "Pad() was meant to pad it, not randomize it. That way all the results are the same length, and can be, for example, inserted in a DWORD[32] array instead of specifing the length of the array".  However, if the string you're attempting to hash is overly long, it's not going to fit into a 128-byte structure.  What that means is that it will probably get truncated, causing a whole mess of collision-issues with long strings. 

Come to think of it, I don't think VB uses Unicode, either.  I'm fairly certain it only uses either plain ASCII or the system-dependent value.
Quote from: Joe on January 23, 2011, 11:47:54 PM
I have a programming folder, and I have nothing of value there

Running with Code has a new home!

Quote from: Rule on May 26, 2009, 02:02:12 PMOur species really annoys me.