HKSecret Part IIV
HKSecret Part IIV
com/hacking
Hacking Ciphers
We can hack the Caesar cipher by using a cryptanalytic technique called “brute-force”. Because
our code breaking program is so effective against the Caesar cipher, you shouldn’t use it to
encrypt your secret information.
Ideally, the ciphertext would never fall into anyone’s hands. But Kerckhoffs’s Principle (named
after the19th-century cryptographer Auguste Kerckhoffs) says that a cipher should still be secure
even if everyone else knows how the cipher works and has the ciphertext (that is, everything
except the key). This was restated by the 20th century mathematician Claude Shannon as
Shannon’s Maxim: “The enemy knows the system.”
5. LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
6.
7. # loop through every possible key
8. for key in range(len(LETTERS)):
9.
10. # It is important to set translated to the blank string so that the
11. # previous iteration's value for translated is cleared.
12. translated = ''
13.
14. # The rest of the program is the same as the original Caesar program:
15.
16. # run the encryption/decryption code on each symbol in the message
17. for symbol in message:
18. if symbol in LETTERS:
19. num = LETTERS.find(symbol) # get the number of the symbol
20. num = num - key
21.
22. # handle the wrap-around if num is 26 or larger or less than 0
23. if num < 0:
24. num = num + len(LETTERS)
25.
26. # add number's symbol at the end of translated
27. translated = translated + LETTERS[num]
28.
29. else:
30. # just add the symbol without encrypting/decrypting
31. translated = translated + symbol
32.
33. # display the current key being tested, along with its decryption
34. print('Key #%s: %s' % (key, translated))
You will see that much of this code is the same as the code in the original Caesar cipher program.
This is because the Caesar cipher hacker program does the same steps to decrypt the key.
The hacker program will create a message variable that stores the ciphertext string the program
tries to decrypt. The LETTERS constant variable contains every character that can be encrypted
with the cipher. The value for LETTERS needs to be exactly the same as the value for LETTERS
used in the Caesar cipher program that encrypted the ciphertext we are trying to hack, otherwise
the hacker program won’t work.
Line 8 is a for loop that does not iterate over a string value, but instead iterates over the return
value from a call to a function named range(). The range() function takes one integer
argument and returns a value of the range data type. These range values can be used in for loops
to loop a specific number of times. Try typing the following into the interactive shell:
More specifically, the range value returned from the range() function call will set the for
loop’s variable to the integers 0 up to, but not including, the argument passed to range(). Try
typing the following into the interactive shell:
Line 8 is a for loop that will set the key variable with the values 0 up to (but not including) 26.
Instead of hard-coding the value 26 directly into our program, we use the return value from
len(LETTERS) so that if we modify LETTERS the program will still work. See the “Encrypt
Non-Letter Characters” section in the last chapter to read why.
So the first time the program execution goes through this loop, key will be set to 0 and the
ciphertext in message will be decrypted with key 0. (The code inside the for loop does the
decrypting.) On the next iteration of line 8’s for loop, key will be set to 1 for the decryption.
You can also pass two integer arguments to the range() function instead of just one. The first
argument is where the range should start and the second argument is where the range should stop
(up to but not including the second argument). The arguments are separated by a comma:
The range() call evaluates to a value of the “range object” data type.
On line 12, translated is set to the blank string. The decryption code on the next few lines
adds the decrypted text to the end of the string in translated. It is important that we reset
translated to the blank string at the beginning of this for loop, otherwise the decrypted text will
be added to the decrypted text in translated from the last iteration in the loop.
caesarHacker.py
14. # The rest of the program is the same as the original Caesar program:
15.
16. # run the encryption/decryption code on each symbol in the message
17. for symbol in message:
18. if symbol in LETTERS:
19. num = LETTERS.find(symbol) # get the number of the symbol
Lines 17 to 31 are almost exactly the same as the code in the Caesar cipher program from the last
chapter. It is slightly simpler, because this code only has to decrypt instead of decrypt or encrypt.
First we loop through every symbol in the ciphertext string stored in message on line 17. On
each iteration of this loop, line 18 checks if symbol is an uppercase letter (that is, it exists in the
LETTERS constant variable which only has uppercase letters) and, if so, decrypts it. Line 19
94 http://inventwithpython.com/hacking
locates where symbol is in LETTERS with the find() method and stores it in a variable called
num.
caesarHacker.py
20. num = num - key
21.
22. # handle the wrap-around if num is 26 or larger or less than 0
23. if num < 0:
24. num = num + len(LETTERS)
Then we subtract the key from num on line 20. (Remember, in the Caesar cipher, subtracting the
key decrypts and adding the key encrypts.) This may cause num to be less than zero and require
“wrap-around”. Line 23 checks for this case and adds 26 (which is what len(LETTERS)
returns) if it was less than 0.
caesarHacker.py
26. # add number's symbol at the end of translated
27. translated = translated + LETTERS[num]
Now that num has been modified, LETTERS[num] will evaluate to the decrypted symbol. Line
27 adds this symbol to the end of the string stored in translated.
caesarHacker.py
29. else:
30. # just add the symbol without encrypting/decrypting
31. translated = translated + symbol
Of course, if the condition for line 18’s condition was False and symbol was not in
LETTERS, we don’t decrypt the symbol at all. If you look at the indentation of line 29’s else
statement, you can see that this else statement matches the if statement on line 18.
String Formatting
caesarHacker.py
33. # display the current key being tested, along with its decryption
34. print('Key #%s: %s' % (key, translated))
Although line 34 is the only print() function call in our Caesar cipher hacker program, it will
print out several lines because it gets called once per iteration of line 8’s for loop.
The argument for the print() function call is something we haven’t used before. It is a string
value that makes use of string formatting (also called string interpolation). String formatting
with the %s text is a way of placing one string inside another one. The first %s text in the string
gets replaced by the first value in the parentheses after the % at the end of the string.
String formatting is often easier to type than string concatenation with the + operator, especially
for larger strings. And one benefit of string formatting is that, unlike string concatenation, you
can insert non-string values such as integers into the string. Try typing the following into the
interactive shell:
Line 34 uses string formatting to create a string that has the values in both the key and
translated variables. Because key stores an integer value, we’ll use string formatting to put
it in a string value that is passed to print().
Summary
The critical failure of the Caesar cipher is that there aren’t that many different possible keys that
can be used to encrypt a message. Any computer can easily decrypt with all 26 possible keys, and
it only takes the cryptanalyst a few seconds to look through them to find the one that is in
English. To make our messages more secure, we will need a cipher that has more possible keys.
That transposition cipher in the next chapter can provide this for us.