0,0 → 1,135 |
""" crypto.keyedHash.tkip_key_mixing.py |
TKIP Temporal Key Mixing Function reference implementation |
|
2002-11-04 |
|
""" |
from struct import pack, unpack |
from binascii_plus import * |
|
def S(word): |
""" TKIP S-Box non-linear substitution of a 16 bit word """ |
return (tkipSbox[0][word & 0x00FF] ^ tkipSbox[1][(word>>8) & 0x00FF]) |
|
""" tkipSbox consists of two 256 word arrays |
The tkip Sbox is formed from the AES/Rijndael Sbox |
""" |
|
from crypto.cipher.rijndael import Sbox |
tkipSbox = [range(256),range(256)] # arbitrary initialization |
for i in range(256): |
k = Sbox[i] # the rijndael S box (imported) |
if k & 0x80 : # calculate k*2 polynomial math |
k2 = (k<<1)^0x11b # reduce by rijndael modulas |
else: |
k2 = k<<1 |
k3 = k ^ k2 |
tkipSbox[0][i] = (k2<<8)^k3 |
tkipSbox[1][i] = (k3<<8)^k2 # second array is just byte swap of first array |
|
def rotR1(v16): |
""" circular right rotate on 16 bits """ |
return ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15)) |
|
class TKIP_Mixer: |
""" The TKIP_Mixer class generates dynamic keys for TKIP based on the |
TK (temporal key), TA and PN |
""" |
def __init__(self, tk1=None, transmitterAddress=None, pnBytes=6*chr(0)): |
""" The TKIP Mixer is initialized with tk1 and TA |
tk1 is a temporal key (16 octet string) |
transmitterAddress is a 6 octet MAC address |
pn is the packet number, here as an integer < (1<<8*6) |
""" |
self.tk = None |
self.ta = None |
self.setPnBytes(pnBytes) # sets self.pnBytes and validates input |
self.upper4SequenceOctets = self.pnBytes[-4:] |
if tk1 != None : |
self.setKey(tk1) |
if transmitterAddress != None : |
self.setTA(transmitterAddress) |
|
def setKey(self, key): |
""" Set the temporal key (tk1) for key mixing """ |
if len(key)!= 16: raise 'Wrong key size' |
# for readability of subroutines, make tk a list of 1 octet ints |
self.tk = [ord(byte) for byte in key] |
if self.ta != None : # reset phase1 value |
self.phase1Key = phase1KeyMixing( self.tk, self.ta, self.pn) |
|
def setTA(self, taBytes): |
""" Set the transmitter address """ |
if len(taBytes) != 6: raise 'Bad size for transmitterAddress' |
self.ta = [ord(byte) for byte in taBytes] |
if self.tk != None : # reset phase1 value |
self.phase1Key = phase1KeyMixing( self.tk, self.ta, self.pn ) |
|
def setPnBytes(self, pnBytes): |
""" Set the pnBytes from the packet number (int) """ |
assert( len(pnBytes)==6 ), 'pnBytes must be 6 octets' |
self.pnBytes = pnBytes |
self.pn = [ord(byte) for byte in pnBytes] # int list for readability |
|
def newKey(self, pnBytes): |
""" return a new 'mixed' key (16 octets) based on |
the pn in 6 octets, also know as TSC |
""" |
assert(self.ta != None), 'No TA' |
assert(self.tk != None), 'No TK' |
self.setPnBytes(pnBytes) |
if self.pnBytes[-4:] != self.upper4SequenceOctets: # check if upper bits change |
# calculate phase1 key only when upper bytes change |
self.upper4SequenceOctets = pnBytes[-4:] |
self.phase1Key = phase1KeyMixing( self.tk, self.ta, self.pn ) |
return phase2KeyMixing( self.tk, self.phase1Key, self.pn ) |
|
def phase1KeyMixing(tk,ta,pn): |
""" Create a p1k (5 integers) from TK, TA and upper 4 octets of sequence number pn""" |
p1k = [0,0,0,0,0] # array of 5 integers (each 2 octets) |
p1k[0] = pn[3]*256 + pn[2] |
p1k[1] = pn[5]*256 + pn[4] |
p1k[2] = ta[1]*256 + ta[0] # 2 octets of MAC as an integer (little-endian) |
p1k[3] = ta[3]*256 + ta[2] # 2 octets of MAC as an integer (little-endian) |
p1k[4] = ta[5]*256 + ta[4] # 2 octets of MAC as an integer (little-endian) |
for i in range(8): |
j = 2*(i&1) |
p1k[0] = ( p1k[0] + S( p1k[4]^(tk[j+ 1]*256 + tk[j+ 0]))) & 0xFFFF |
p1k[1] = ( p1k[1] + S( p1k[0]^(tk[j+ 5]*256 + tk[j+ 4]))) & 0xFFFF |
p1k[2] = ( p1k[2] + S( p1k[1]^(tk[j+ 9]*256 + tk[j+ 8]))) & 0xFFFF |
p1k[3] = ( p1k[3] + S( p1k[2]^(tk[j+13]*256 + tk[j+12]))) & 0xFFFF |
p1k[4] = ( p1k[4] + S( p1k[3]^(tk[j+ 1]*256 + tk[j])) + i ) & 0xFFFF |
return p1k |
|
def phase2KeyMixing(tk,p1k,pn): |
""" Create a 16 octet key from the phase1Key (p1k) |
and 2 octets of sequence counter """ |
ppk = [i for i in p1k] |
ppk.append( p1k[4] + pn[1]*256 + pn[0] ) # append value for ppk[5] |
# Bijective non-linear mixing of the 96 bits of ppk |
ppk[0] = (ppk[0] + S(ppk[5] ^ (tk[1]*256 + tk[0]) )) & 0xFFFF |
ppk[1] = (ppk[1] + S(ppk[0] ^ (tk[3]*256 + tk[2]) )) & 0xFFFF |
ppk[2] = (ppk[2] + S(ppk[1] ^ (tk[5]*256 + tk[4]) )) & 0xFFFF |
ppk[3] = (ppk[3] + S(ppk[2] ^ (tk[7]*256 + tk[6]) )) & 0xFFFF |
ppk[4] = (ppk[4] + S(ppk[3] ^ (tk[9]*256 + tk[8]) )) & 0xFFFF |
ppk[5] = (ppk[5] + S(ppk[4] ^ (tk[11]*256+ tk[10]) )) & 0xFFFF |
# Final sweep |
ppk[0] = (ppk[0] + rotR1(ppk[5] ^ (tk[13]*256+tk[12]))) & 0xFFFF |
ppk[1] = (ppk[1] + rotR1(ppk[0] ^ (tk[15]*256+tk[14]))) & 0xFFFF |
ppk[2] = (ppk[2] + rotR1(ppk[1])) & 0xFFFF |
ppk[3] = (ppk[3] + rotR1(ppk[2])) & 0xFFFF |
ppk[4] = (ppk[4] + rotR1(ppk[3])) & 0xFFFF |
ppk[5] = (ppk[5] + rotR1(ppk[4])) & 0xFFFF |
|
rc4Key = range(16) |
rc4Key[0] = pn[0] |
rc4Key[1] = (pn[0] | 0x20) & 0x7F |
rc4Key[2] = pn[1] |
rc4Key[3] = 0xFF &((ppk[5]^(tk[1]*256+tk[0]))>>1) |
for i in range(6): |
rc4Key[4+2*i] = ppk[i] & 0xff |
rc4Key[5+2*i] = (ppk[i]>>8) & 0xff |
wepSeed = ''.join([chr(i) for i in rc4Key]) # convert to string |
return wepSeed |
|
|