############################################################################## # - CMSC 443H - STEPHENS - MAY 2006 || XOR HASH || ############################################################################## # # Hashing function that compresses a string consisting of any number of # characters: A-Z,a-z,0-9,+,/ to 8 of these characters. It is intended that # the compression should change a lot, even during small changes. # # Usage: # Simply run the script with Python and then send the script the character # string through standard in. The hash is now sent to standard out. # python xorhash.py < file # or # python xorhash.py # /text/ # # Algorithm: # For each character in the input string, convert it to a 48 bit character # string by applying a different XOR logic statement for every bit. These # are all the possible XOR statements comprised of all the bits. For example, # some XOR functions include (numbers being the bit #): # 1 xor 3 # 1 xor 5 # 2 xor 3 xor 5 # 4 # 0 xor 1 xor 2 xor 3 xor 4 xor 5 # 0 xor 1 xor 3 xor 4 xor 5 # The output from each bit is then xor'd to the current compression. Note # also that every other bit checked is complemented; this is used to # complicate things further. # # To keep things interesting, the order in which the xor tests are performed # are in no particular order. Also, the characters are shuffled at the # beginning. Note that the program is seeded the same number every time # so that the randomness stays the same. # # All characters that are not included in the alphabet described above are # completely ignored and do not change the hash whatsoever. # # It is important to note that the file 'xortests.txt' is required since it # is used to load the XOR rules used. This file exists an this was done this # way because writing out all the possible tests was easier than to think of # a way to compute it. # # Original project description: # 5. Recently secure hash methods have drawn attention because, # under computational pressure, they have yielded collisions # which is considered a weakness. The feeling is if collisions # can be discovered then collisions can be engineered. This project # requires you to read ahead and study hash methods. The project # here is to construct a hash method. You can either: # # b) a) construct a textual hash method which maps a file of # text to a hash string of 8 hash characters. A text file # here will be considered a file of upper/lower alphabetic # characters, digits, and the characters + and / ( a base # 64 format) # You should try to make your hash as secure as possible. # It shouldn't be immediately obvious how to create collisions, # etc. # points 50-70 # estimated difficulty: easy to medium # ############################################################################### from sys import stdin from sys import argv from random import seed from random import shuffle # Always seed the number so that the randoness stays the same seed(71) # The list of xor tests, shuffled xor = [ [ int(num) for num in line.split() ] for line in open('xortests.txt').readlines() ] shuffle(xor) # The alphabet chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" # The hashes to be used to store the numerical values of characters char_values = {} num_values = {} i = 0 for c in chars: char_values[c] = i num_values[i] = c i += 1 # Converts a numerical value to a string def val2string(value): string = "" for i in range(8): string += num_values[value % 64] value /= 64 return string # Converts a string to a numerical value def string2vals(string): return [ char_values[c] for c in string if c in char_values.keys() ] # Converts a value to a list of 6 bits def val2bits(value): bits = [] for i in range(6): bits.append(value % 2) value /= 2 return bits # Converts a list of bits to a value def bits2val(bits): place = 1 value = 0 for n in bits: value += n * place place *= 2 return value # Expands a list of 6 bits to a list of 48 bits def bits248(bits, xor): count = 0 out = [] for i in range(48): val = 0 for n in xor[0]: if count % 2: val ^= bits[n] else: val ^= not bits[n] count += 1 xor = xor[1:] + xor[:1] out.append(val) return out # XORs a lits of 48 bits to the hash def add2hash(hash_values, bits): for i in range(len(hash_values)): hash_values[i] ^= bits[i] ############# MAIN ################ # Initial hash value cur_values = [0]*48 # Read in the text and convert it to lists of bits text_bits = [ val2bits(val) for val in string2vals(stdin.read()) ] # Shuffle them up shuffle(text_bits) # Compute each's expansion and XOR it to the current hash for bits in text_bits: add2hash(cur_values,bits248(bits,xor)) # Output the hash print val2string(bits2val(cur_values))