def super_decrypt(self, msg, digraphOverride=None, zeroSystem=False): diFreq = DigraphFrequency() letFreq = LetterFrequency() if digraphOverride is None: (mfd, mfdf) = diFreq.getFrequencies(msg)[1][0] else: # most frequent digraph mfd = digraphOverride mfdIntsTuple = diFreq.digraphToIntTuple(mfd, zeroSystem) mfdConsts = [mfdIntsTuple + (diFreq.letToInt('t', zeroSystem),), mfdIntsTuple + (diFreq.letToInt('h', zeroSystem),)] followingDigraphs = diFreq.getFollowingDigraphs(msg, mfd) followingDigraphConstants = [diFreq.digraphToIntTuple(diTup, zeroSystem) + (diFreq.letToInt('e', zeroSystem),) for diTup in followingDigraphs] # the possible values of a and b in the key matrix: # a b # c d abConsts = mfdConsts[0] abPossibleValues = [self.solveLinEquPair(abConsts, folDiConsts) for folDiConsts in followingDigraphConstants] mostLikelyABValues = self.mostFreqIntPairs(abPossibleValues) bestABValues = [] for abValue, count in mostLikelyABValues: # if the abValue works for all equations, it is very likely # that it is the correct values for a and b if count == len(followingDigraphConstants): bestABValues.append(abValue) # if there are still no abValues # (i.e. no a, b pair works for all of the equations # created by assuming that the digraphs following the mfd correspond to 'e*') # then just pick the top 2 if not bestABValues: bestABValues = mostLikelyABValues[:2] # if there are two a,b pairs to try out, do the following if len(bestABValues) > 1: # of the two most likely values for both a and b, go through every digraph in the message # and determine the int value of a1x+b1y, and a2x + b2y where x and y are the two letters # in the digraph and a1,b1 and a2,b2 are the abValues # convert the resulting int values to letters, and see which key pair produced the more # frequent letter # keep a running tally of the more frequent letters for each pair to see which one is # more likely to be the actual key key1 = bestABValues[0][0] key2 = bestABValues[1][0] msgDigraphs = diFreq.getUniqueDigraphs(msg) key1Lets = [self.diAndKeyToLet(digraph, key1, zeroSystem) for digraph in msgDigraphs] key2Lets = [self.diAndKeyToLet(digraph, key2, zeroSystem) for digraph in msgDigraphs] englishLetterFrequenciesDict = letFreq.getStandardFrequencies()[0] key1MoreFreqCounter = 0 key2MoreFreqCounter = 0 for i in range(0, len(key1Lets)): if englishLetterFrequenciesDict[key1Lets[i]] > englishLetterFrequenciesDict[key2Lets[i]]: key1MoreFreqCounter += 1 else: key2MoreFreqCounter += 1 # try the more likely key first! abKeys = [key1, key2] if key1MoreFreqCounter > key2MoreFreqCounter else [key2, key1] print "Key %s is the more likely of the keys %s and %s" % (abKeys[0], key1, key2) # there is only one AB value, so it must be the correct key pair for a,b!!! else: abKeys = bestABValues # find possible values for c and d that solve the equation cdConsts = mfdConsts[1] cdKeys = self.solveLinEqu(cdConsts) ## print out a description of the progress thus far if digraphOverride is None: print "\nThe most frequent digraph (MFD) in the message was:\n\t%s' with frequency %0.2f%%" % (mfd, mfdf) else: print "\nThe most frequent digraph (MFD) in the message was manually set as:\n\t%s'" % (mfd) print "\nMapping '%s' to 'th' resulted in the following equations:\n\t%da + %db = %d\n\t%dc + %dd = %d" % (mfd, abConsts[0], abConsts[1], abConsts[2], cdConsts[0], cdConsts[1], cdConsts[2]) print "\nLooking at digraphs following '%s' resulted in the following digraphs:\n\t%s" % (mfd, followingDigraphs) print "\nMapping the above digraphs to 'e*' resulted in the following equations:" for fdc in followingDigraphConstants: print "\t%da + %db = %d" % (fdc[0], fdc[1], fdc[2]) print "\nSolving for 'a' and 'b' in these equations resulted in the following most\nlikely key(s):" for abKey in abKeys: print "\ta = %d, b = %d" % (abKey[0], abKey[1]) print "\nSolving for 'c' and 'd' in the original set of equations resulted in the\nfollowing most likely key(s):" for cdKey in cdKeys: print "\tc = %d, d = %d" % (cdKey[0], cdKey[1]) print "\nThese keys as matrices in the form [[a, b], [c, d]] will now be brute forced so \nthat the user can attempt to spot the correct deciphering of the ciphertext.\n\n" for abKey in abKeys: for cdKey in cdKeys: key = [list(abKey), list(cdKey)] print "Trying decryption key: %s, encryption key %s" % (key, self.matrixOps.invertMatrix(key)) print self.decrypt(msg, key, False, zeroSystem)