Skip to content
Newer
Older
100644 77 lines (62 sloc) 4.31 KB
c4fd6ab @asweigart Pylint-suggested fixes.
authored Aug 25, 2012
1 # Null Cipher Breaker
2 # http://inventwithpython.com/codebreaker (BSD Licensed)
3
4 import nullCipher, pyperclip, detectEnglish
f16b361 @asweigart Initial commit.
authored Aug 19, 2012
5
6 # There are two settings our breaking program needs to limit the range of the possible keys it checks.
7 # 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.
8 # 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'
9 # 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.
10 MAX_KEY_NUMBER = 9
11 MAX_KEY_LENGTH = 5
12
13 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.'
14 #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.
15
16 def main():
17 # 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.
18 possibleKeys = 0 # start the number of keys at 0.
19 for i in range(1, MAX_KEY_LENGTH + 1):
20 # 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.
21 # 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.
22 possibleKeys += MAX_KEY_NUMBER ** i
23
24 # 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.
25 print('Max key number: %s' % MAX_KEY_NUMBER)
26 print('Max key length: %s' % MAX_KEY_LENGTH)
27 print('Possible keys to try: %s' % (possibleKeys))
28 print()
29
30 # Python programs can be stopped at any time by pressing Ctrl-C (on Windows) or Ctrl-D (on Mac and Linux)
31 print('(Press Ctrl-C or Ctrl-D to quit at any time.)')
32 print('Breaking...')
33
34 # The breakNull() function will have all the encryption breaking code in it, and return the original plaintext.
35 brokenMessage = breakNull(myMessage)
36
91f8abb @asweigart First round of personal fixes. This is an unhelpful log message.
authored Aug 24, 2012
37 if brokenMessage != None:
f16b361 @asweigart Initial commit.
authored Aug 20, 2012
38 # The plaintext is displayed on the screen. For the convenience of the user, we copy the text of the code to the clipboard.
39 print('Copying broken message to clipboard:')
40 print(brokenMessage)
41 pyperclip.copy(brokenMessage)
91f8abb @asweigart First round of personal fixes. This is an unhelpful log message.
authored Aug 25, 2012
42 else:
43 print('Failed to break encryption.')
f16b361 @asweigart Initial commit.
authored Aug 20, 2012
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)
c4fd6ab @asweigart Pylint-suggested fixes.
authored Aug 25, 2012
58 percentEnglish = round(detectEnglish.getEnglishCount(decryptedText) * 100, 2)
f16b361 @asweigart Initial commit.
authored Aug 20, 2012
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
91f8abb @asweigart First round of personal fixes. This is an unhelpful log message.
authored Aug 25, 2012
69 if response.strip().upper().startswith('D'):
f16b361 @asweigart Initial commit.
authored Aug 20, 2012
70 return decryptedText
71 trialKey = getNextKey(trialKey)
91f8abb @asweigart First round of personal fixes. This is an unhelpful log message.
authored Aug 25, 2012
72 print('Failed to break encryption.')
f16b361 @asweigart Initial commit.
authored Aug 20, 2012
73 return None
74
75
76 if __name__ == '__main__':
91f8abb @asweigart First round of personal fixes. This is an unhelpful log message.
authored Aug 25, 2012
77 main()
Something went wrong with that request. Please try again.