Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 82 lines (67 sloc) 4.649 kb
f16b361 @asweigart Initial commit.
authored
1 # Null Cipher Breaker, http://inventwithpython.com/codebreaker (BSD Licensed)
2 import copy, time
3 import nullCipher, pyperclip, transpositionBreaker
4
5 # There are two settings our breaking program needs to limit the range of the possible keys it checks.
6 # MAX_KEY_NUMBER is the range of numbers it checks for each number in the key. A MAX_KEY_NUMBER value of 9 means it will check the numbers 0 through 9.
7 # MAX_KEY_LENGTH is the largest amount of numbers in the key. A MAX_KEY_LENGTH value of 5 means that the key could be something like '1 2 3 4 5' or '1 1 1 1 1' or '1 2 3 4', but not '1 2 3 4 5 6'
8 # If these numbers are too large, then breaking the code will take a long time. If these numbers are too small, then the breaking program won't be able to break the encryption.
9 MAX_KEY_NUMBER = 9
10 MAX_KEY_LENGTH = 5
11
12 myMessage = 'kWhhbe#n n>IP uTksEe b<aZ wXCo(rdq7,( iActy moveeanggsU jCku2stmT dwhlvaPt FZIx czyhtoo(&sxe SUi6t Ylt#o 3kmCeaU5nb -rR-b nbLegitOTh6eroN Jmogzr2e Lgnpor/0 GleOjs.s.'
13 #W h e n I u s e a w o rd , i t m eans just what I choose it to mean -- neither more nor less.
14
15 def main():
16 # As a convenience to the user, we will calculate the number of keys that the current MAX_KEY_LENGTH and MAX_KEY_NUMBER settings will cause the breaker program to go through.
17 possibleKeys = 0 # start the number of keys at 0.
18 for i in range(1, MAX_KEY_LENGTH + 1):
19 # In order to find the total number of possible keys, we need to add the total number of keys of 1 number, of 2 numbers, of 3 numbers, and so on up to MAX_KEY_LENGTH numbers.
20 # To find the number of keys with i numbers in them, we multiply the range of numbers (that is, MAX_KEY_NUMBER) by itself i times. That is, we find MAX_KEY_NUMBER to the ith power.
21 possibleKeys += MAX_KEY_NUMBER ** i
22
23 # After exiting the loop, the value in possibleKeys is the total number of keys for MAX_KEY_NUMBER and MAX_KEY_RANGE. We then print this data to the user.
24 print('Max key number: %s' % MAX_KEY_NUMBER)
25 print('Max key length: %s' % MAX_KEY_LENGTH)
26 print('Possible keys to try: %s' % (possibleKeys))
27 print()
28
29 # Python programs can be stopped at any time by pressing Ctrl-C (on Windows) or Ctrl-D (on Mac and Linux)
30 print('(Press Ctrl-C or Ctrl-D to quit at any time.)')
31 print('Breaking...')
32
33 # The breakNull() function will have all the encryption breaking code in it, and return the original plaintext.
34 brokenMessage = breakNull(myMessage)
35
36 if brokenMessage == None:
37 # breakNull() will return the None value if it was unable to break the encryption.
38 print('Breaking failed. Unable to break this ciphertext.')
39 else:
40 # The plaintext is displayed on the screen. For the convenience of the user, we copy the text of the code to the clipboard.
41 print('Copying broken message to clipboard:')
42 print(brokenMessage)
43 pyperclip.copy(brokenMessage)
44
45
46 def breakNull(ciphertext):
47 # The program needs to try keys of length 1 (such as '5'), of length 2 (such as '5 5'), and so on up to length MAX_KEY_LENGTH.
48 # This is because the key '1 0' will decrypt differently than '1 0 0'.
49 for trialKeyLength in range(1, MAX_KEY_LENGTH + 1):
50 # We will be using the "list of int values" for of keys. The string form like '4 2 3' that we use in the original encryption program is used just because it makes it easier to type for the user.
51 # We use list replication (multiplying a list value by an int value) to get the starting key.
52 trialKey = [0] * trialKeyLength
53
54 trialKey = getNextKey(trialKey)
55
56 while trialKey != [0] * trialKeyLength:
57 decryptedText = nullCipher.decryptMessage(ciphertext, trialKey)
58 percentEnglish = round(transpositionBreaker.getEnglishCount(decryptedText) * 100, 2)
59 if percentEnglish > 0:
60 print('Key %s decrypts to %s%% English.' % (trialKey, percentEnglish))
61 if percentEnglish >= 25:
62 print()
63 print('Possible encryption break:')
64 print('Key ' + str(trialKey) + ': ' + decryptedText[:100])
65 print()
66 print('Enter D for done, or just press Enter to continue breaking:')
67 response = input('> ')
68
69 if response.upper().startswith('D'):
70 return decryptedText
71 trialKey = getNextKey(trialKey)
72 print('No decryptions found. Code breaking has failed.')
73 return None
74
75
76 if __name__ == '__main__':
77 key = [0] * 4
78 while True:
79 key = getNextKey(key)
80 print(key)
81
82 #main()
Something went wrong with that request. Please try again.