diff --git a/rainbow_generator.py b/rainbow_generator.py new file mode 100644 index 0000000..3a72165 --- /dev/null +++ b/rainbow_generator.py @@ -0,0 +1,213 @@ +import pearson +import random + +defaultCharset="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + +def targetHashFunction(value): + """ A wrapper around the actual hash function so we can make some measurements about what has been done. """ + nBytes=2 + h=pearson.hashN(value,nBytes) + try: + targetHashFunction.counter += 1 + if not h in targetHashFunction.seen: + targetHashFunction.seen.append(h) + else: + targetHashFunction.collisions+=1 + except AttributeError: + targetHashFunction.counter = 1 + targetHashFunction.seen=[] + targetHashFunction.collisions=0 + return h + + +def makeGuess(value, i, minLen,maxLen,charset, debug=False): + """ Given a value and an index, return a new valid input. + + Arguments: + value -- a hash value to be turned into a new guess + i -- the number of steps along the chain we are + minLen -- minimum length of a new guess + maxLen -- maximum length of a new guess + charset -- string containing the valid characters for a guess + debug -- set to True for copious output, useful for debugging + """ + + #Use value as seed, i as offset + random.seed(value) + + #Move along the pseudo-random sequence by i*maxLen steps + #Prevents situations where the random length + random selection means i has no impact on output + for x in range(i*maxLen): + random.random() + + #Determine a length of the guess + l=random.randint(minLen,maxLen) + guess="".join(random.choices(charset, k=l)) + + if debug: print(f"Making guess from [{value}], with offset {i}, minLen {minLen}, maxLen {maxLen} and charset {charset}: {guess}") + + return guess + + + +def queryTable(hashValue,table, chainLength, hashFunc=targetHashFunction, guessFunc=makeGuess, minLen=3, maxLen=6, charset=defaultCharset, debug=False): + """find a chain that contains an input value that results in the + given hash, in the given table. chainLength limits the search since + there is no point building test chains longer than the ones in the + table + + Arguments: + hashValue -- value being searched + table -- the table to search + hashFunc -- the hash function being used. Should accept a string parameter. + guessFunc -- the function to be used to generate new guesses. Should accept a byte string and an index + minLen -- minimum length of potential guesses + maxLen -- maximum length of potential guesses + charset -- string of valid characters for guesses + debug -- set to True for lots of debug output + + """ + # Start with the easy case. Is it the end of a chain, and therefore recorded already? + if hashValue in table: + if debug: print(f"Found hash in chain at final position, beginning with {table[hashValue]}") + attempt= rebuildChain(table[hashValue],hashValue,hashFunc,guessFunc,chainLength,minLen,maxLen,charset) + if attempt!=None: + return attempt + + #If not, we try recreating chains from each position to see if we find a match. + for i in range(chainLength-1,-1,-1): + if debug: print(f"Trying at chain point {i}") + h=hashValue + g=None + out="" + for j in range(i,chainLength): + g=guessFunc(h,j, minLen=minLen, maxLen=maxLen, charset=charset) + h=hashFunc(g) + if debug: out+=f"({g}->{h}) " + if debug: print(out) + if h in table: + if debug: print(f"Found hash in chain at position {i}, beginning with {table[h]}") + attempt= rebuildChain(table[h],hashValue, hashFunc, guessFunc, chainLength,minLen, maxLen, charset, debug=False) + if attempt!=None: + return attempt + if debug: print("No matches found") + return None + + + +def rebuildChain(chain,targetHash, hashFunc, guessFunc, chainLength,minLen, maxLen, charset, debug=False): + """ Recreates a single chain, looking for a target hash. + + Arguments: + chain -- the starting value for the chain + targetHash -- the hash we are looking for + hashFunc -- the hash function being used. Should accept a string parameter. + guessFunc -- the function to be used to generate new guesses. Should accept a byte string and an index + minLen -- minimum length of potential guesses + maxLen -- maximum length of potential guesses + charset -- string of valid characters for guesses + debug -- set to True for lots of debug output + """ + v=chain + h=hashFunc(v) + if debug: print(f"Searching for {targetHash} in the chain beginning with {chain}") + for i in range(chainLength): + if debug: print(f"Current value is {v} (hash: {h}) at position {i}") + if hashFunc(v)==targetHash: + if debug: print(f"Dehashed as {v}") + return v + v=guessFunc(h,i,minLen=minLen, maxLen=maxLen, charset=charset) + h=hashFunc(v) + if debug: print("Failed to recreate :/") + return None + +def generateTable(chainStarts, hashFunc, guessFunc, chainLength, minLen=3,maxLen=6,charset=defaultCharset): + """ Create a rainbow table for the given hash function + + Arguments: + chainStarts -- a list of starting values. The length of this list determines how many chains will be constructed. + hashFunc -- a hash function to be used in the hashing step. + guessFunc -- a function that can produce valid inputs to the hash function. The function should accept a value and the keyword arguments `minLen` (minimum guess length) `maxLen` (maximum guess length) and `charset` (a string containing all valid characters to be used in the table). These will be passed directly from the arguments of the same names given to this funciton. + chainLength -- length of each chain + minLen -- minimum length of values to be hashed + maxLen -- maximum length of values to be hashed + charset -- string containing all valid characters for values being hashed + +""" + Rainbow={} + ## Defines the dictionary + + for Guess1 in chainStarts: + + Guesses=Guess1 + hash = hashFunc(Guess1) + x=0 + + while x < chainLength: + Guess1 = guessFunc(hash, x, minLen, maxLen, charset) + hash = hashFunc(Guess1) + x+=1 + + Rainbow[hash] = Guesses + return Rainbow + ## Returns the rainbow tables hashed guesses that have been generated + + +if __name__=="__main__": + + rows=2000 + columns=500 + starts=[] + i=0 + while len(starts)