Advertisement
Guest User

Cipher Cracker

a guest
Jun 22nd, 2015
5,332
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.58 KB | None | 0 0
  1. from math import log
  2. import re
  3. import os
  4.  
  5. class VCipher:
  6.     def __init__(self):
  7.         self.Alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  8.         self.Frequencies = {
  9.             'A':84, 'B':23, 'C':21, 'D':46, 'E':116, 'F':20, 'G':25, 'H':49, 'I':76,
  10.             'J':2,  'K':5,  'L':38, 'M':34, 'N':66,  'O':66, 'P':15, 'Q':2,  'R':64,
  11.             'S':73, 'T':81, 'U':19, 'V':11, 'W':21,  'X':2,  'Y':24, 'Z':3
  12.         }
  13.  
  14.         for k in self.Frequencies.keys():
  15.             self.Frequencies[k] = self.Frequencies[k]/1000.0
  16.  
  17.         self.Bans = {}
  18.         for a in self.Alphabet:
  19.             x = (25 * self.Frequencies[a]) / (1 - self.Frequencies[a])
  20.             x = log(x) / log(10)
  21.             self.Bans[ord(a) - ord('A')] = x
  22.  
  23.     def TuringCheck(self, cipherText, keyLength, resultCount):
  24.         ByLetter = {}
  25.         for a in self.Alphabet:
  26.             ByLetter[a] = []
  27.             ordVal = ord(a) - ord('A')
  28.             for col in range(0, keyLength):
  29.                 i = col
  30.                 Evidence = 0
  31.                 while i < len(cipherText):
  32.                     cipherVal = ord(cipherText[i]) - ord('A')
  33.                     diff = (cipherVal - ordVal) % 26
  34.                     Evidence += self.Bans[diff]
  35.                     i += keyLength
  36.                 ByLetter[a].append(Evidence)
  37.         Result = []
  38.         for i in range(0, keyLength):
  39.             Column = {}
  40.             for l in self.Alphabet:
  41.                 Column[l] = ByLetter[l][i]
  42.             Result.append(Column)
  43.         return self._GetLikelyPasswords(Result, resultCount)
  44.  
  45.     def Encrypt(self, plainText, key):
  46.         CipherText = ''
  47.         KeyPos = 0
  48.         for l in plainText:
  49.             if l in self.Alphabet:
  50.                 lV = ord(l) - ord('A')
  51.                 kV = ord(key[KeyPos].upper()) - ord('A')
  52.                 val = (lV + kV) % 26
  53.                 CipherText += chr(val + ord('A'))
  54.                 KeyPos = (KeyPos + 1) % len(key)
  55.             elif l.upper() in self.Alphabet:
  56.                 lV = ord(l) - ord('a')
  57.                 kV = ord(key[KeyPos].lower()) - ord('a')
  58.                 val = (lV + kV) % 26
  59.                 CipherText += chr(val + ord('a'))
  60.                 KeyPos = (KeyPos + 1) % len(key)
  61.             else:
  62.                 CipherText += l
  63.         return CipherText
  64.  
  65.     def Decrypt(self, cipherText, key):
  66.         PlainText = ''
  67.         KeyPos = 0
  68.         for l in cipherText:
  69.             if l in self.Alphabet:
  70.                 lV = ord(l) - ord('A')
  71.                 kV = ord(key[KeyPos].upper()) - ord('A')
  72.                 val = (lV - kV) % 26
  73.                 PlainText += chr(val + ord('A'))
  74.                 KeyPos = (KeyPos + 1) % len(key)
  75.             elif l.upper() in self.Alphabet:
  76.                 lV = ord(l) - ord('a')
  77.                 kV = ord(key[KeyPos].lower()) - ord('a')
  78.                 val = (lV - kV) % 26
  79.                 PlainText += chr(val + ord('a'))
  80.                 KeyPos = (KeyPos + 1) % len(key)
  81.             else:
  82.                 PlainText += l
  83.         return PlainText
  84.  
  85.     def _Factor(self, n):
  86.         return set(reduce(list.__add__, ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))
  87.  
  88.     def _FindRepeatedSubstrings(self, cipherText, subLength):
  89.         Subs = {}
  90.         for i in range(0, len(cipherText) - subLength):
  91.             Substring = cipherText[i:i+subLength]
  92.             if cipherText.count(Substring) > 1 and not Substring in Subs.keys():
  93.                 Subs[Substring] = [m.start() for m in re.finditer(Substring, cipherText)]
  94.                
  95.         return Subs
  96.  
  97.     def _AddToCountDict(self, d, v):
  98.         if not v in d.keys(): d[v] = 1
  99.         else: d[v] += 1
  100.  
  101.     def Crack(self, cipherText, pathToEnglishDict, candidateCount, passPercentage):
  102.         print "Cracking...\n{0}".format(cipherText)
  103.         with open(pathToEnglishDict) as f:
  104.             Dictionary = [x.strip('\n') for x in f.readlines()]
  105.         Trimmed = self.Trim(cipherText)
  106.         KeyLengthsDict = self.GetLikelyKeyLengths(Trimmed)
  107.         KeyLengths = sorted(KeyLengthsDict, key= KeyLengthsDict.__getitem__, reverse=True)
  108.         print "Found {0} candidate key lengths".format(len(KeyLengths))
  109.         for length in KeyLengths:
  110.             print "Testing Length: {0}".format(length)
  111.             Keys = self.TuringCheck(Trimmed, length, candidateCount)
  112.             for key in Keys:
  113.                 print "     Testing Key: {0}".format(key)
  114.                 PlainText = self.TrimWithSpaces(self.Decrypt(cipherText, key))
  115.                 Words = PlainText.split()
  116.                 EnglishWordCount = 0
  117.                 for word in Words:
  118.                     if word in Dictionary: EnglishWordCount += 1
  119.                 Percentage = float(EnglishWordCount) / len(Words)
  120.                 print "          Percentage of english words in sample: %{0}".format(Percentage * 100)
  121.                 if Percentage >= (passPercentage/100.0):
  122.                     print "-------------"
  123.                     print "Cracked!"
  124.                     print "Key = {0}".format(key)
  125.                     print self.Decrypt(cipherText, key)
  126.                     return
  127.         print "No key found... try other cyphers"
  128.  
  129.  
  130.  
  131.     def GetLikelyKeyLengths(self, cyphertext):
  132.         Substrings = self._FindRepeatedSubstrings(cyphertext, 3)
  133.         Diffs = []
  134.         for substring in Substrings.keys():
  135.             for i in range(0, len(Substrings[substring])-1):
  136.                 Diffs.append(Substrings[substring][i+1] - Substrings[substring][i])
  137.         FactorCounts = {}
  138.  
  139.         for d in Diffs:
  140.             Factors = self._Factor(d)
  141.             for f in Factors:
  142.                 self._AddToCountDict(FactorCounts, f)
  143.         return FactorCounts
  144.  
  145.  
  146.     def _GetLikelyPasswords(self, columns, count):
  147.         ColumnLetters = []
  148.         Counts = []
  149.         for ranks in columns:
  150.             ColumnLetters.append(sorted(ranks, key=ranks.__getitem__, reverse=True))
  151.             Counts.append(0)
  152.  
  153.         Results = []
  154.         ResultCount = 0
  155.         while ResultCount < count:
  156.             BestPass = ""
  157.             SmallestDiff = 1000
  158.             SmallestCol = -1
  159.             for i in range(0, len(columns)):
  160.                 BestPass += ColumnLetters[i][Counts[i]]
  161.                 if Counts[i] < 25:
  162.                     V1 = columns[i][ColumnLetters[i][Counts[i]]]
  163.                     V2 = columns[i][ColumnLetters[i][Counts[i]+1]]
  164.                     Diff = V1 - V2
  165.                     if Diff < SmallestDiff:
  166.                         SmallestDiff = Diff
  167.                         SmallestCol = i
  168.             Counts[SmallestCol] += 1
  169.             Results.append(BestPass)
  170.             ResultCount += 1
  171.         return Results
  172.  
  173.     def TrimWithSpaces(self, text):
  174.         result = ''
  175.         for l in text:
  176.             if l.upper() in self.Alphabet or l == ' ':
  177.                 result += l.upper()
  178.         return result  
  179.  
  180.     def Trim(self, text):
  181.         result = ''
  182.         for l in text:
  183.             if l.upper() in self.Alphabet:
  184.                 result += l.upper()
  185.         return result
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement