# Cryptography

## 1 Cracking the Caesar Cipher

### Learn It

• It's trivial for a cracker to figure out your password if you don'e choose a strong and secure password.
• As most people stupidly use the same password for many sites, the cracker would probably then have their main password.
• One of the best ways of learning how to stop crackers, is to learn how they are able to attack encryption schemes.
• We'll start of by learning how to crack the Caesar Cipher.

### Try It

• Here's a message that has been encrypted using the Caesar Cipher.
```odmhxf dmzqa, ljqruh wkrvh iluvw wzr zrugv wkhb duh mxvw wkhuh wr frqixvh d fudfnhu.
dqbzdb wkh vhfuhw phvvdjh lv, qrergb hashfwv wkh vsdqlvk lqtxlvlwlrq
```
• Can you figure out what the message says?

### Code It

• Given enough time, you could probably decrypt the message, but it could take you awhile.
• A computer can do it pretty quickly though.

### Code It

• Let's start with a couple of variables with the information we need.
• Open up a new python file (CC-crack.py) in IDLE and add the following lines of code.
```alphabet = 'abcdefghijklmnopqrstuvwxyz'
cipherText = '''odmhxf dmzqa, ljqruh wkrvh iluvw wzr zrugv wkhb duh mxvw wkhuh wr
frqixvh d fudfnhu. dqbzdb wkh vhfuhw phvvdjh lv,
qrergb hashfwv wkh vsdqlvk lqtxlvlwlrq'''
```
• In Python, if we want a multiline string, we use three quotes '''

### Design It

• The algorithm for this isn't too complicated.
• We're basically going to try all 25 possible shift values on the secret message.

### Learn It

• We've used a `for` loop before to iterate over a string of characters.
```text = 'the quick brown fox jumped over the lazy dog'
for letter in text:
print(letter)
```
• But we can also use for loops to iterate over a range of numbers
```for i in range(10):
print(i)

for i in range(5, 20):
print(i)

for i in range(10, 100, 5):
print(i)

for i in range(10, 0, -1):
print(i)

for i in range(10, -20, -1):
print(i)
```

### Badge It - Silver

• Create a new file called forLoops.py
• For each of the `for` loops above, describe what they print out.
• Construct `for` loops to print out the following.
1. All the numbers from 1 to 1000
2. All the even numbers from 100 to 200
3. All the numbers going backwards from 500 to 0 that are divisible by 10

### Code It

• Put these lines of code into your file.
```for i in range(1, 26):
plainText = ''
```
• This will give use all the shift values as the variable `i`
• It also creates an empty string, ready to build the decrypted text.

### Learn It

• We now want to iterate over the letters in the cipherText.
• We can do this with another `for` loop.
• Placing one `for` loop inside another `for` loop is called nesting

### Code It

• Change your code so it looks like this.
```alphabet = 'abcdefghijklmnopqrstuvwxyz'
cipherText = '''odmhxf dmzqa, ljqruh wkrvh iluvw wzr zrugv wkhb duh mxvw wkhuh wr
frqixvh d fudfnhu. dqbzdb wkh vhfuhw phvvdjh lv,
qrergb hashfwv wkh vsdqlvk lqtxlvlwlrq'''

for i in range(1, 26):
plainText = ''
for letter in cipherText:
position = alphabet.index(letter)
shiftedIndex = position + i
shiftedLetter = alphabet[shiftedIndex]
print(shiftedLetter)
```
• When you run this code, you should get the following error
```Traceback (most recent call last):
File "/path/to/file/filename.py", line 9, in <module>
position = alphabet.index(letter)
ValueError: substring not found
```

### Try It

• So what has gone wrong?
• Let's use a trace table to figure it out.
• Trace tables, trace the values of variables in our code
• The variables i, letter, position and shiftedLetter keep changing as the loop runs.
i letter position shiftedIndex shiftedLetter
1 o 14 15 p
1 d 3 4 e

### Badge It - Gold

• Try to complete the trace table
• You should see that there is a problem with the code.
• Identify the problem and write a description of why the program crashes.

### Code It

• As spaces aren't in our alphabet, we need a way of handling them in our code.
• While we're at it, we might as well handle other characters that are not in the alphabet, such as numbers and punctuation.
• We can use conditional selection to achieve this.
• Create a new Python file to practice conditional selection.
• Let's start off in the Interpreter
• Type the following
```myVar = 10
myVar < 10
```
• You should see the word `False` appear
• Now try the following statements
```myVar > 10
myVar = 10
```
• We can use the fact that these statements evaluate to `True` or `False` to make decisions in our program.
• Create a new Python file to practice in. You can delete it later.
```myVar = 10
if myVar > 10:
print('Greater than 10')
elif myVar < 10:
print('Less than 10')
else:
print('Equal to 10')
```
• Run this program.
• Conditional statements work by evaluating whether a statement is `True` or `False`
• So in the above example, `myVar <10` evaluates to False.
• Now change the value of myVar and have a look at the results.

### Code It

• So how does this help us?
• Try typing the following lines into the interpreter.
```myLetters = 'abcdefg'
'a' in myLetters
'g' in myLetters
' ' in myLetters
'?' in myLetters
```
• So we can detect if a character is missing from a string of characters and then use conditionals to make different choices.

### Code It

• Let's try and use what you have learned to make our program work a little better.
• Use the structured English below to help you build the program in Python.
```1. For i being every number from 1 through to 26...
2. Set plainText to an empty string
3. For every letter in cipherText
4. If the letter is not in alphabet then set shiftedLetter to letter
5. Else set index to letter's position in the alphabet
6. Set shiftIndex to index + i
7. Set shiftedLetter to the letter at shiftIndex in the alphabet
8. Add the shifted Letter to the plainText
9. Print the plainText once the second For loop ends.
```
• Run your code again.
• You should get a new error that looks like this.
```Traceback (most recent call last):
File "/path/to/python/file.py", line 14, in <module>
shiftedLetter = alphabet[shiftIndex]
IndexError: string index out of range
```
• If you don't get that error `string index out of range` then keep trying or ask for some help.

### Try It

• So what does `string index out of range` mean?
• Let's go back to the interpreter to try and see if we can reproduce the error.
```myString = 'abcdefg'
myString[3]
myString[7]
```
• We get the same error. There is no 7th element of the string as we start counting from 0, so the last letter is actually the 6th element.
• We have the same problem in our code.
• As we add `i` to the letters position, eventually we're going to get a number larger than 25, and there are only positions in our alphabet string are 0..25

### Learn It

• Luckily there is a simple operator that can solve this for us.
• If our program is trying to look up the value of the 26th element in the string, we actually want it to find the 0th element of the string. If it's trying to look up the 29th element of the list, we want it to actually look up the 3rd item.
• The modulo operator finds the remainder after division. In Python we use the `%` symbol.

### Try It

• In the interpreter try the following.
```12 % 26
26 % 26
29 % 26
```
• Hopefully you can see how this can help us out. If not, then ask your teacher or a peer for a little help.

### Badge It - Platinum

• Let's try and finish off our program now.
```alphabet = 'abcdefghijklmnopqrstuvwxyz'
cipherText = '''odmhxf dmzqa, ljqruh wkrvh iluvw wzr zrugv wkhb duh mxvw wkhuh wr
frqixvh d fudfnhu. dqbzdb wkh vhfuhw phvvdjh lv,
qrergb hashfwv wkh vsdqlvk lqtxlvlwlrq'''

for i in range(1,26):
plainText = ''
for letter in cipherText:
if

else:

plainText += shiftedLetter
print('With a shift of',i,'the message is\n\n',plainText,'\n')
```
• You need to complete the program by completing the conditional statements.
• When you run the program, you should get 25 attempts at decryption, one of which should make sense.