Skip to content

Commit

Permalink
Final documentation project2
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Kiær committed Jun 27, 2013
1 parent 146c9bc commit 56af1da
Show file tree
Hide file tree
Showing 5 changed files with 262,122 additions and 262,054 deletions.
23 changes: 23 additions & 0 deletions project2/README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,27 @@ A simulated TMTO-attack of car-key authentication system using Rainbow-tables.
parameters and hardcoded `u`
* `RainbowAttack.py` - Script using the Rainbow-table to crack
hardcoded `u`
* `table.csv` - Rainbowtable generated from TableGenerator.py
* `test.py` - Used to test the Rainbowtable as we had lots of problems with the generating the table.

*NOTE:* As we have discussed, our rainbowtable attack is not fully functional. We don't know why and what we are doing wrong, but the success rate is extremely low. We have testet our tables, and they are infact correct. Our only guess right now, is the computation of the respone r's successors is wrong or we have misunderstood how to do it.

## Attack idea

Our attacker is a person who tries to steal the car. He proceeds as follows:

* He picks an arbitrary, fixed challenge u and precomputes a Rainbow Table for the function f(s) = lowest 28 bit of MD5(s||u).
* When he gets access to a car key for a short time, he presses the button on the key fob. Then he acts on behalf of the car by sending a challenge u and receiving the response r.
* He now uses his Rainbow Table to find a value s with f(s) = r.
* He verifies this secret by sending some trial challenges to the key fob and checking whether he can compute the right response. If he can, then he has found the correct secret, meaning that he now can open the car at will.

## Rainbowtable attacks described

Rainbowtables are a time memory tradeoff attack, wich makes it possible to crack hashed passwords. Rainbowtables computes a table of m rows and t chains, only storing the random selected starting point and the computed end point. Each computation in the chain applies a reduction function on the hashed values.

The reduction functions of a rainbow table are all different (one per column), but are generally built as an extension of a single reduction function.

In our example we use the reduction function f(s) = (s + 1) % BITSIZE.

## Usage

Expand All @@ -19,12 +39,15 @@ parameters. The resulting table is printed to a cvs called `table.cvs`. It
is run with, simply:

$ python TableGenerator.py

The generated table should now contain 2^18 rows and with the chains included around 2^28 covered points(this will be lower, cause of collisions).

`RainbowAttack.py` uses the previously created Rainbow-table and
hardcoded `u` to search for a matching key `s`.

$ python RainbowAttack.py

RainbowAttack computes all the successor of a response r (computed from the given equations), and checks if any of these successors is in the loaded table. If a successor is equal to an endpoint, this row will be used to compute the password. The startpoint of the table is used to compute the chain of reduction functions. If one of these functions matches r, the value before should be the password. This is not 100% certain, as the could be in the table without the key being there.

## Logic

Expand Down
67 changes: 47 additions & 20 deletions project2/RainbowAttack.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,36 @@
#

from termcolor import colored
import md5, random, csv
import md5, random, csv, os

BIT_SIZE = 28
CHAIN_LEN = 2**10
TABLE_NAME = "table.csv"
SERIAL_NO = "0123456"

#s = hex(random.getrandbits(BIT_SIZE))[:-1]
s ='0xebd305f'
#s ='0x46d2260'
s ='0x8b392c4'
#s ='0x31e6ee3'
#s ='0x56259ab'
#s = hex(random.randint(16777216, 268435455))

u = "daffeda"

def reduction(cipher, iteration = 0):
"""Lowest 28 bits of (MD5(s||u) % i).
Reduction function from the rainbow tables.
Returns the hex value"""
return hex((int(cipher, 16) + iteration) % 2**BIT_SIZE)[-BIT_SIZE/4 - 3: -1]

def md5_hash(s):
"""Hashes the original string and returns a hex string"""
return '0x' + md5.new(str(s) + str(u)).hexdigest()[:-1]

def f(s, i=0):
"""Lowest 28 bits of (MD5(s||u) % i)"""
digest = '0x' + md5.new(str(s) + str(u)).hexdigest()[-BIT_SIZE/4:]
result = hex((int(digest, 16) + i) % 2**BIT_SIZE)
return result
#def f(s, i=0):
# """Lowest 28 bits of (MD5(s||u) % i)"""
# digest = '0x' + md5.new(str(s) + str(u)).hexdigest()
# result = hex((int(digest, 16) + i) % 2**BIT_SIZE)[:BIT_SIZE/4+2]
# return result


def read_table():
Expand All @@ -40,35 +53,49 @@ def read_table():


def find_key(table, r):
"""Search for matching respons in Rainbow-table"""
"""Search for matching respons in Rainbow-table
First generates the successors of r.
Then checks through the loaded rainbowtable if any matching values between the successors and the rainbowtable are found.
If a match is found, the starting point of the given match is used to compute the predecessor of r.
The predecessor of r, should be the key we are looking for."""
#Initialize the list of successors of r.
succ = [r]
for i in xrange(0, CHAIN_LEN):
succ.append(f(succ[i-1], i))
#Fills the list of successors of r.
for i in xrange(1, CHAIN_LEN):
succ.append(reduction(md5_hash(succ[i - 1]), i))

#Looks through the dictonary given in the input.
for key, value in table.iteritems():
#If a value is in the successor list, ss = key.
if value in succ:
print "\tCollition: %s -> %s" % (key, value)
print succ.index(value)
ss = key
for i in xrange(0, succ.index(value) - 1):
rs = f(ss, i)
# print "%s" % rs,
#Starts with ss and computes the predecessor of r.
for i in xrange(0, CHAIN_LEN):
rs = reduction(md5_hash(ss), i)
#if rs is equal to r, then the key should've been found.
if rs==r:
#returns the predecessor.
return ss
ss = rs
print rs
return -1


def main():
"""main method for Rainbow attack on a car."""
os.system('clear')
#Printouts for console.
print " Fob > Hello, key fob no. %s is here!" % SERIAL_NO

print " Eve > Challenge: 0x%s" % u

r = f(s)
#Generates r
r = reduction(md5_hash(s))
print " Fob > Response: %s" % r

#loads the table from the csv file.
table = read_table()
print " Eve > Cracking..."

#Tries to find the key
key = find_key(table, r)

if key is -1:
Expand Down
39 changes: 23 additions & 16 deletions project2/TableGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,36 +11,45 @@

import md5, random, csv, time

#Constants used to create the table.
BIT_SIZE = 28
NUM_CHAINS = 2**18
CHAIN_LEN = 2**10
TABLE_NAME = "table.csv"
TABLE_NAME = "tabletest.csv"
LOG_FREQ = 5000

#Challenge key u
u = "daffeda"

def reduction(cipher, iteration):
"""Lowest 28 bits of (MD5(s||u) % i)"""
return hex((int(cipher, 16) + iteration) % 2**BIT_SIZE)[-BIT_SIZE/4 - 3: -1]

def md5_redux(s, i=0):
"""Lowest 28 bits of (MD5(s||u) % i)"""
digest = '0x' + md5.new(str(s) + str(u)).hexdigest()[-BIT_SIZE/4:]
result = hex((int(digest, 16) + i) % 2**BIT_SIZE)
return result

def md5_hash(s):
"""Hashes the original string and returns a hex string"""
return '0x' + md5.new(str(s) + str(u)).hexdigest()[:-1]

def generate_table():
"""Generates a rainbow table"""
"""Generates a rainbow table.
Fills a hashtable with random generated start points and their corresponding endpoints.
Runs through the given number of chains and length of each chain. Ends of with writing the dictonary to a .csv file."""
dict = {}

#Runs the loop through the number of chains
for i in xrange(0, NUM_CHAINS):
red = hex(random.getrandbits(28))[:-1]

red = hex(random.randint(16777216, 268435455))

#Random generated startpoint.
red_start_point = red

#Computes the end point, by hashing the start point through the number of chains.
for x in xrange(0, CHAIN_LEN):
red = md5_redux(red, x)
cipher = md5_hash(red)
red = reduction(cipher, x)

#Endpoint for storage in table.
red_end_point = red

#Prints ammount of times loop has run.
if i % LOG_FREQ == 0:
print "Took i calls: %d" % (i)
dict[red_start_point] = red_end_point
Expand All @@ -56,14 +65,12 @@ def write_to_csv(dict):


def main():
"""Tool for generating a rainbowtable from given constants."""
start = time.clock()

generate_table()

generate_table()
end = time.clock()
print "Took: ", (end - start), " s"


if __name__ == '__main__':
main()

Loading

0 comments on commit 56af1da

Please sign in to comment.