# Reduction function Generation

I think I know how rainbow table works , I just wanted to make basic reduction function(for md5) in python with an approach that I am not taking a certain portion of hash but am taking the full hash and introducing below reduction function with an error handling method below is code.

Q1. is it necessary to take first or last or a portion of hash, what i mean is say a03d4d52516c03932b6815fe6c6f4151 (hexdigest) for this hash can i take every 8 bit and try to convert it to ASCII if that fails / goes out of ASCII range(90) then do nothing and try for next 8 bit. Please be informed i generated hash using utf-8 encoding.

Q2. Even i am able to generate plain text but result contains null bytes and if i use strip() to get rid of null bytes to generate the next hash on plain text result then hash changes. does md5 calculate on null bytes too ?

Result: v;92T/Mm - first plain text with no split() - hash=87aef402508bc715a1cf37b7ffe3c7ea

    v;92T/Mm - first plain text with split() to get rid of null bytes
hash=fc9d09e27c4ee842f7e262eb6a190da1


Code I tried(please run it to validate:

# PYTHON 3.1

"""Trying a basic reduction function R1 , md5 Rainbow table new apporoach. here am not taking ony last x bits of hexdihest hash always, it is randomized through error checking Conventional reference: How to create reduction functions in rainbow tables?"""

import hashlib, functools, time, codecs

# 1. Constant hash function to be applied on the domain of P of f(H); where p belongs to P which is a finite set of alphanumeric character

def H(p): return hashlib.md5(p.encode('utf-8')).hexdigest()

# 2. constant split function to operate on 8 bit ascii char set

l=lambda x:x+2

Note I could do a utf-16 and 16 bits operation to generate other european charcter; but I only want to reduce hexdigest of hash to ascii readable char.

Note If i use utf-16 then it will give me again 128 bits printable charactr in return as i dont need to put any error checking to get the result !

p=input("Gimme your password !\n")

h=H(p)

def R1(h):
L=[]
x=0
for i in range(0,16):
bit_op_8=h[x:l(x)]
x+=2
try:
L.append(codecs.decode(codecs.decode(bit_op_8,'hex'),'ascii'))

except UnicodeDecodeError:
pass

c=""
for j in range(0,len(L)):
c+=L[j]
return c

result=R1(h)

print("after Reduction: ",result)


# 3.second hashing: f(H1)=f(H) but H1 takes R1(f(H))

#Here without using a strip() and not caring about null bytes
reduced=result
print(H(reduced))

#Here including nullbytes in result
reduced=result
reduced1=str(reduced).strip()
print(H(reduced1))

• After posting this code looks uglier then my married ex! let see one more time. – secinfo098 Feb 16 '19 at 15:03
• Some part of this question is not belongs to Cryptography, rather belongs to SO. – kelalaka Feb 16 '19 at 15:17
• @kelalaka got your point, would you tell me whether or not taking last or first few hexdigits to make plain text out of md5 hash is mandatory while applying reduction function? or i just can do like above method ? – secinfo098 Feb 16 '19 at 15:23
• You are free to choose any reduction function. Using first 8-bit or last 8-bit has no difference. Why don't you take mod 90 for every 8-bit? – kelalaka Feb 16 '19 at 15:41