def createHashTablesecond(self): """ eliminate as many keys as possible, brute force the remaining ones by calling tryencryption() """ print "Testing..." nbTried = 0 self.temp = CMEA() print "K4" for k4 in xrange(128): print k4 for k5 in xrange(256): for (k6,k7) in self.possible67: tpp = [self.calcpp(a,ta,k4,k5,k6,k7) for (a,ta) in self.tuples] if [] in tpp: continue for (a,b,c,d) in [(a,b,c,d) for a in tpp[0] for b in tpp[1] for c in tpp[2] for d in tpp[3]]: m = ((a-d)%256,(b-d)%256, (c-d)%256) m = m[0]*256**2 + m[1]*256+m[2] if m in self.startmap: for k in self.startmap[m]: nbTried = nbTried + 1 key = k[:3] key.append((a-k[3])%256) key.extend([k4,k5,k6,k7]) if self.trialencryption(key): print "key found: ",key print "this key may not be the exact same one, but it is equivalent..." print "keys tried: ", nbTried return True
def __init__(self): nbplaintext = 80 self.p0 = [ [ True for i in range(256) ] for j in range(256) ] for i in range(256): for j in range(256): if(not ((j-i) % 256) in cavetable): self.p0[i][j] = False self.CVI = CVInverse() self.p = None self.c = CMEA() self.texts = self.createPlaintexts(nbplaintext, self.c)
class Cryptanalysis3B: def __init__(self): nbplaintext = 80 self.p0 = [ [ True for i in range(256) ] for j in range(256) ] for i in range(256): for j in range(256): if(not ((j-i) % 256) in cavetable): self.p0[i][j] = False self.CVI = CVInverse() self.p = None self.c = CMEA() self.texts = self.createPlaintexts(nbplaintext, self.c) def getY1Z1(self, x, P, C): return (P[0] + x) % 256, (C[0] + x) % 256 def checkValue(self, T0, p, P, C): """ for a given T0 possible value, and a given (P, C) we eliminate all we can """ y1, z1 = self.getY1Z1(T0, P, C) change = False for guess in range(256): if(p[y1 ^ 1][guess]): #T(y1 ^ 1) = guess Pp1 = (P[1] + guess) % 256 #P'(1) == P'(n-2) Ppp1 = Pp1 % 256 #Tz1 -> T(z1 ^ 1) Tz1 = (Ppp1 - C[1]) % 256 y2 = (y1 + Pp1) % 256 z2 = (z1 + Ppp1) % 256 #P'2 avec ambiguité sur le LSB Pp0 = (P[0] + T0) % 256 Pp2 = (Pp0 ^ (C[0] + T0)) % 256 #C[0] + T0 = Ppp0 #T(y2 ^ 2) sauf LSB Ty20 = (Pp2 - P[2]) % 256 Ty21 = ((Pp2 ^ 1) - P[2]) % 256 Ppp2 = Pp2 % 256 #T(z2 ^ 2) sauf LSB Tz20 = (Ppp2 - C[2]) % 256 Tz21 = ((Ppp2 ^ 1) - C[2]) % 256 if(not p[z1 ^ 1][Tz1]): p[y1 ^ 1][guess] = False change = True if((not p[y2 ^ 2][Ty20] or not p[z2 ^ 2][Tz20]) and (not p[y2 ^ 2][Ty21] or not p[z2 ^ 2][Tz21])): p[y1 ^ 1][guess] = False change = True return change def buildP(self): """ we initialize the matrix p, eliminating all values not in the Cave Table """ self.p0 = [ [ True for i in range(256) ] for j in range(256) ] for i in range(256): for j in range(256): if(not ((j-i) % 256) in cavetable): p0[i][j] = False def copyP(self): p = [ q[:] for q in self.p0 ] return p def checkT0Value(self,x): """ check if T(0) = x is possible """ p = self.copyP() continuer = True while(continuer): continuer = False for (P, C) in self.texts: continuer = continuer or self.checkValue(x, p, P, C) for (C, P) in self.texts: continuer = continuer or self.checkValue(x, p, P, C) for i in range(256): if(not (True in p[i])): return False self.p = p return True def findT0(self): """ find T(0) value by calling checkT0Value on every x in the Cave Table """ print "finding T(0) value..." for x in range(256): if(x in cavetable and self.checkT0Value(x)): print x, "(y)" self.myt0=x else: print x, "(n)" print "T(0) =", self.myt0 def createPlaintexts(self, n, c, size=3): """ create n random plaintexts (the known plaintexts) """ r = random. Random() l = [] print "T(0)", c.Tbox(0) c.blocksize = size for i in range(n): P=[r.randint(0,255) for k in range(size)] l.append((P, c.crypt(P))) return l def getPossible67values(self): """ find the possible K6, K7 values """ s = set() possible = [] for k in cavetable: s.add(k) print "finding possible K6,K7 values..." print "K6" for k6 in xrange(128): print k6 for k7 in xrange(256): exit=False broke=False for i in range(256): jfound=False for ctv in s: j = (i+ cavetable[(((ctv+i)^k6)+k7)%256])%256 if(self.p[i][j]): jfound=True break if not jfound: broke = True break if not broke: possible.append((k6,k7)) self.possible67 = possible print "K6, K7", len(self.possible67), "possible values" def get4tuples(self): """ find 4 (a, T(a)) """ sortie = [] for i in range(256): t = [k for k in range(256) if self.p[i][k]==True] if len(t)==1: sortie.append((i, t[0])) self.tuples = sortie[:4] def calcp(self, x, k0, k1, k2): return ((cavetable[((x^k0)+k1) %256] +x)^k2) %256 def createHashTableprime(self): """ builds the hashmap """ print "building hashmap..." self.startmap = {} print "K0" for k0 in xrange(128): print k0 for k1 in xrange(256): for k2 in xrange(128): tp = [self.calcp(x, k0, k1 ,k2) for (x, tx) in self.tuples] n = [(p - tp[3]) %256 for p in tp[:3]] n = n[0]*256**2+n[1]*256+n[2] if not n in self.startmap: self.startmap[n]=[] self.startmap[n].append([k0,k1,k2, tp[0]]) def calcpp(self, a, ta , k4, k5 ,k6 ,k7): res = [(ta-a) %256] res2 = [] for r in res: for i in self.CVI.getinverse(r): res2.append((((i -k7 )^k6)-a) %256) res = [] for r in res2: for i in self.CVI.getinverse(r): res.append(((((i)-k5)^k4)-a)%256) res2 = [] for r in res: for i in self.CVI.getinverse(r): res2.append(i) return res2 def createHashTablesecond(self): """ eliminate as many keys as possible, brute force the remaining ones by calling tryencryption() """ print "Testing..." nbTried = 0 self.temp = CMEA() print "K4" for k4 in xrange(128): print k4 for k5 in xrange(256): for (k6,k7) in self.possible67: tpp = [self.calcpp(a,ta,k4,k5,k6,k7) for (a,ta) in self.tuples] if [] in tpp: continue for (a,b,c,d) in [(a,b,c,d) for a in tpp[0] for b in tpp[1] for c in tpp[2] for d in tpp[3]]: m = ((a-d)%256,(b-d)%256, (c-d)%256) m = m[0]*256**2 + m[1]*256+m[2] if m in self.startmap: for k in self.startmap[m]: nbTried = nbTried + 1 key = k[:3] key.append((a-k[3])%256) key.extend([k4,k5,k6,k7]) if self.trialencryption(key): print "key found: ",key print "this key may not be the exact same one, but it is equivalent..." print "keys tried: ", nbTried return True def trialencryption(self, key): """ brute force on the remaining keys """ self.temp.setkey(key) good=True for (P,C) in self.texts: if (not P==self.temp.crypt(C) or not C == self.temp.crypt(P)): good = False break return good #we begun to parallelized but did not go too far... def findT0parallel(self): n = 8 threadlist = [] for i in range(n): t = range(i*256/n, (i+1)*256/n) threadlist.append(Parallel(t,self.c ,self.texts, self)) for t in threadlist: t.start() sortie = [] for t in threadlist: t.join() sortie.extend(t.l) self.myt0=sortie[0]
# if one of the value if knwon (because the cave table invalidate one of the option) we can deduce the other value posj = [tj, tj + 1] posz = [(tj - c) % 256, (tj + 1 - c) % 256] posj = [k for k in posj if (k - j) % 256 in cavetable] posz = [k for k in posz if (k - z) % 256 in cavetable] if len(posj) == 1: self.known[j] = posj[0] if len(posz) == 1: self.known[z] = posz[0] return compteur if __name__ == '__main__': d = Decrypter() d.setCrypter(CMEA()) d.c.blocksize = 3 d.c.createRandomKey() possibilities = d.findTzero() print "number of possible values for t0:", len(possibilities) for p in possibilities: # checks if the value for t0 is correct t = d.findPossibleOthers(p) if t != []: break d.getallconstraints(t[0][0]) for i in range(10): print "number of Tbox output known at iteration ", i, " :", len( d.known)