\chapter{Case study 2}

To wrap-up this course, we are going to look at a case study in which
we implement a simple cryptography encoder and editor for text files.
This case study will bring together several aspects of the topics you
have been learning over the past several weeks including: files,
strings, GUI programming, and dictionaries. And, along the way, we're
going to see what it's like to really think like a computer scientist.

\section{Program Design}

Whenever we come across a new programming task, the first decision to
be made is always to decide on the design methodology --- in other
words, how are you going to design the program. There are many
different methodologies, but I am fond of following the open source
mantra: ``Release Early, Release Often''. In this methodology, you
start with a working program, continuously make small changes, all
the while maintaining a working program. This sort of method is good
for small projects, but can be hopeless for very large projects. One
of the limitations is that the complexity of the program often spirals
out of control and the design degenerates into a hopeless mess. For
this reason, it is also important that you refactor the code often.
Refactoring means reorganising the code so that it is easier to
understand and maintain.

Even given a design methodology, there are at least two ways of
approaching the solution strategy: user-driven or programmer-driven.
In a user-driven solution, the programmer is always thinking about
what the user wants and not necessarily what's easiest for the
programmer. Programmer-driven is the reverse, focusing on what is
easiest for the programmer, rather than what is most useful for the
user. Generally, user-driven solutions produce useful programs for
users, and programmer-driven solutions produce a program that only the
programmer can use.

So, let's think about the sort of things a user would want from a
program for encrypting and editing text files:
\begin{itemize}
\item open a file
\item encrypt or decrypt a file
\item edit a file
\item save the file to disk
\item quit the program
\end{itemize}
Is there anything else a user might be concerned about?
\begin{answerspace}



zend
\end{answerspace}

That's pretty much it for a bare-bones text editor and encryptor.
Let's get coding.

\section{The Initial Program}
Before actually starting to code, there is another decision to be
made. Should we develop the GUI first and add the functionality later,
or the functionality first and the GUI later? There's no hard and fast
rule for this question, and in many cases it depends on the task at
hand. For this problem it probably makes sense to develop in a GUI
first manner.

First, let's get a basic text window up and running.
\pythoninline{Tkinter} has a text widget called \pythoninline{Text}
which we could use. But with larger documents we will need to be able
to scroll the text and the \pythoninline{Text} widget doesn't supply
that functionality. Luckily, there is a slightly more advanced widget
in the \pythoninline{ScrolledText} module. Following is code for
creating a basic scrolled text window.

\begin{minipage}{\textwidth}
\begin{python}
import Tkinter
import ScrolledText

if __name__ == "__main__":
    root = Tkinter.Tk()
    textWidget = ScrolledText.ScrolledText(root, width=80, height=50)
    textWidget.pack()

    root.mainloop()
\end{python}
\end{minipage}

Notice how we're using the ``Release Early, Release Often'' method. We
already have a working program!

\section{Opening a File}
The next step is to add an option for opening and loading in a file.
The usual way of providing file opening operations is via a menu bar.
We haven't met menu bars in \pythoninline{Tkinter} as yet, but they
are quite straightforward. In the following code we add a menu bar
with a file option.

\begin{minipage}{\textwidth}
\begin{python}
import Tkinter
import ScrolledText

def open_command():
    print "hello"

if __name__ == "__main__":
    root = Tkinter.Tk()
    textWidget = ScrolledText.ScrolledText(root, width=80, height=50)
    textWidget.pack()

    menuBar = Tkinter.Menu(root, tearoff=0)
    fileMenu = Tkinter.Menu(menuBar, tearoff=0)
    fileMenu.add_command(label="Open", command=open_command)
    menuBar.add_cascade(label="File", menu=fileMenu)
    root.config(menu=menuBar)

    root.mainloop()
\end{python}
\end{minipage}

You will notice several things about the above program. First, a
top-level menu bar (called \pythoninline{menuBar}) is created. This is
followed by the creation of a second level menu bar (called
\pythoninline{fileMenu}). We can add as
many menus as we like, but in this application, only one is needed. To
\pythoninline{fileMenu} we added a command which is simply a Python
function. So far, the command doesn't do anything very interesting,
but we still have a working program.

To open a file, we can use a \pythoninline{tkFileDialog}:

\begin{minipage}{\textwidth}
\begin{python}
import tkFileDialog
def open_command():
    global textWidget
    file = tkFileDialog.askopenfile()
    if file != None:
        contents = file.read()
        textWidget.delete("1.0", ScrolledText.END)
        textWidget.insert(ScrolledText.END, contents)
\end{python}
\end{minipage}
This function now does several things. It gets a file via the
\pythoninline{tkFileDialog.askopenfile()} method, reads the contents
of the file into a string, deletes any text currently in the main
window and then inserts the text from the file into the window. The
\pythoninline{textWidget.delete} and \pythoninline{textWidget.insert}
methods deserve some extra attention. 

The
\pythoninline{textWidget.delete} method takes two indexes and deletes all the
text between the first index and up to but not including the last
index. The string \pythoninline{"1.0"} is a specially formatted index
string of the form \pythoninline{LINE\_NUMBER.CHARACTER}. So,
\pythoninline{"1.0"} refers to line 1, character 0
\footnote{Curiously, line numbers start at 1 and character numbers
start at 0}. The constant \pythoninline{ScrolledText.END} refers to
the end of the text.

The \pythoninline{textWidget.insert} method takes just one index and
inserts its second parameter just before the character specified by
the first parameter. The result of the whole function is to read all
the text in from a file and replace the text in
\pythoninline{textWidget} with the file contents.

\section{Saving to a File}

To save to a file, we essentially reverse the process, again using the
\pythoninline{tkFileDialog}:

\begin{minipage}{\textwidth}
\begin{python}
def save_command():
    global textWidget
    file = tkFileDialog.asksaveasfile()
    if file != None:
        # slice off the last character from get, as an extra return is added
        contents = textWidget.get("1.0", ScrolledText.END)[:-1]
        file.write(contents)
        file.close()
\end{python}
\end{minipage}

At this point, we have a quite usable text editor. You could even use
it to write Python programs if you wanted to. The full listing is
given in Figure \ref{fig-cs2-filesave}.
(I've added a Quit menu option as well):

\begin{figure}
\begin{python}
import Tkinter
import ScrolledText
import tkFileDialog

def open_command():
    global textWidget
    file = tkFileDialog.askopenfile()
    if file != None:
        contents = file.read()
        textWidget.delete("1.0", ScrolledText.END)
        textWidget.insert(ScrolledText.END, contents)

def save_command():
    global textWidget
    file = tkFileDialog.asksaveasfile()
    if file != None:
        contents = textWidget.get("1.0", ScrolledText.END)[:-1]
        file.write(contents)
        file.close()
    
def exit_program():
    global root
    root.destroy()

if __name__ == "__main__":
    root = Tkinter.Tk()
    textWidget = ScrolledText.ScrolledText(root, width=80, height=50)
    textWidget.pack()

    menuBar = Tkinter.Menu(root, tearoff=0)
    fileMenu = Tkinter.Menu(menuBar, tearoff=0)
    fileMenu.add_command(label="Open", command=open_command)
    fileMenu.add_command(label="Save", command=save_command)
    fileMenu.add_separator()
    fileMenu.add_command(label="Quit", command=exit_program)
    menuBar.add_cascade(label="File", menu=fileMenu)
    root.config(menu=menuBar)

    root.mainloop()
\end{python}
\caption{A program for loading, editing and saving a
  file \label{fig-cs2-filesave}.}
\end{figure}

\section{Encrypting the Contents}

Our next task is to encrypt the contents and to do this we are going
to use a very simple encryption algorithm called a Vigenere
\myidx{cipher}\footnote{Cipher is another word for encryption
algorithm.}. A Vigenere cipher is a variant of a Caesar cipher, so
let's look at the Caesar cipher first. As you might have guessed, the
Caesar cipher was invented by Julius Caesar to communicate with his
generals. The Caesar cipher is very simple and involves replacing any
given character by a different character using a substitution. The
most common substitution is a ``rotation'' where each character is
replaced by a character $n$ characters away in the alphabet. For
example, if I apply a rotation of 1 or 2 characters to all upper case
characters, I get the following substitution table:
\begin{center}
\tiny
\begin{tabular}{|l|cccccccccccccccccccccccccc|}
\hline
Rotate&A&B&C&D&E&F&G&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V&W&X&Y&Z\\
\hline
1&B&C&D&E&F&G&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V&W&X&Y&Z&A\\
2&C&D&E&F&G&H&I&J&K&L&M&N&O&P&Q&R&S&T&U&V&W&X&Y&Z&A&B\\
\hline
\end{tabular}
\end{center}
The top row of the table indicates the input character, and the
subsequent rows indicates the output character based on a rotation of
1 or 2 characters. Can you see why we call it a rotation? What is the
maximum rotation we can perform?

How can we represent the rotation in Python? Well, we could use a
dictionary which has a character as the key and another character as
the value like so:

\begin{minipage}{\textwidth}
\begin{python}
caesar = dict()
caesar["A"] = "B"
caesar["B"] = "C"
caesar["C"] = "D"
caesar["D"] = "E"
caesar["E"] = "F"
...
\end{python}
\end{minipage}
And then when we wanted to encrypt a character we could simply say:

\begin{minipage}{\textwidth}
\begin{python}
newchar = caesar[oldchar]
\end{python}
\end{minipage}
or something similar. 

However, there is a simpler way involving the
use of the functions \pythoninline{ord} and \pythoninline{chr}. The
\pythoninline{ord} function returns the integer representation of 
a character: 

\begin{minipage}{\textwidth}
\begin{python}
>>> ord('a')
97
>>> ord('A')
65
>>>
\end{python}
\end{minipage}
This example explains why \pythoninline{'Apple'~$<$~'apple'} evaluates
to \pythoninline{True}. The problem of using numbers to encode
alphabets is a fairly complex one. The \pythoninline{ord} function
uses a character set called \myidx{ASCII} (American Standard Code for
Information Interchange) which is a simple and commonly used character
set, but is neither universal nor particularly versatile. It is often
used to encode English text, but is hopeless for other languages
(including Latin languages such as French). The \myidx{Unicode}
character set is
rather more versatile and is a global standard, but due to its
complexity, we won't use it here. ASCII uses the numbers from 32 to
126 to represent printable characters, and some of the numbers from 0
to 31 for various control codes (such as end of line). The
\pythoninline{chr} function is the inverse of the \pythoninline{ord}
function. If you pass it a number between 32 and 126, it will return a
printable character:

\begin{minipage}{\textwidth}
\begin{pythonInteractive}
>>> chr(35)
'#'
>>> chr(90)
'Z'
\end{pythonInteractive}
\end{minipage}

Now we can convert characters into numbers and vice versa, so we might
be tempted to implement a Caesar cipher like this:

\begin{minipage}{\textwidth}
\begin{python}
def caesarEncrypt(char, rotateBy):
    return chr(ord(char)+rotateBy)
\end{python}
\end{minipage}

\begin{minipage}{\textwidth}
What is wrong with that function?
\begin{answerspace}



zend
\end{answerspace}
\end{minipage}
What we really want to do is limit the results of
\pythoninline{ord(char)+rotateBy} to be between $0$ and $126$ which we
can do by using \myidx{modulo arithmetic}. We've seen the modulus
operator in Lecture 2. %\ref{lec-variables}. 
A more correct Caesar cipher
can be written as:

\begin{minipage}{\textwidth}
\begin{python}
def caesarEncrypt(char, rotateBy):
    return chr((ord(char)+rotateBy)%127)
\end{python}
\end{minipage}
Actually, there is a technical issue with \pythoninline{chr(0)} and
the \pythoninline{ScrolledText} widget that is singularly
uninteresting. Suffice to say that we need to use a modified version
to get the Caesar cipher to work with the \pythoninline{ScrolledText}
widget:

\begin{minipage}{\textwidth}
\begin{python}
def caesarEncrypt(char, rotateBy):
    return chr((ord(char)+rotateBy)%126+1)
\end{python}
\end{minipage}
Can you tell what the difference between the two functions is?

\begin{minipage}{\textwidth}
\begin{answerspace}



zend
\end{answerspace}
\end{minipage}

To decrypt, we can simply invert the Caesar cipher function:

\begin{minipage}{\textwidth}
\begin{python}
def caesarDecrypt(char, rotateBy):
    return chr((ord(char)-rotateBy-1)%126)
\end{python}
\end{minipage}

We could, if we wished, use \pythoninline{caesarEncrypt} and
\pythoninline{caesarDecrypt} to encrypt our files, but such an
encryption algorithm is trivially easy to break (see the laboratory
exercises below). A Vigenere cipher makes use of a Caesar cipher but
is much more difficult to break (although not impossible, except in
very limiting circumstances). The Vigenere cipher simply encrypts each
character in the input string with a potentially different
\pythoninline{rotateBy} value. Since \pythoninline{rotateBy} values
are limited to between $0$ and $126$ anyway, it makes sense to use a
string representation of the \pythoninline{rotateBy} values. In other
words, a password:

\begin{minipage}{\textwidth}
\begin{python}
def encrypt(inString, password):
    outString = ""
    index = 0
    for ch in inString:
        ch = caesarEncrypt(ch, ord(password[index]))
        outString = outString + ch
        index = (index+1)%len(password)
    return outString

def decrypt(inString, password):
    outString = ""
    index = 0
    for ch in inString:
        ch = caesarDecrypt(ch, ord(password[index]))
        outString = outString + ch
        index = (index+1)%len(password)
    return outString
\end{python}
\end{minipage}

Take some time to look at these functions and make sure you understand
what is going on.

\section{Putting it All Together}
It's now a fairly simple matter to put the encryption algorithm into
our program. We simply add another drop-down menu which includes the
encryption options, and make use of the
\pythoninline{tkSimpleDialog.askstring} method which can get a string
from the user, resulting in the following completed program:

\begin{python}
import Tkinter
import ScrolledText
import tkFileDialog
import tkSimpleDialog

def open_command():
    global textWidget
    file = tkFileDialog.askopenfile()
    if file != None:
        contents = file.read()
        textWidget.delete("1.0", ScrolledText.END)
        textWidget.insert(ScrolledText.END, contents)

def save_command():
    global textWidget
    file = tkFileDialog.asksaveasfile()
    if file != None:
        contents = textWidget.get("1.0", ScrolledText.END)[:-1]
        file.write(contents)
        file.close()
    
def exit_program():
    global root
    root.destroy()

def caesarEncrypt(char, rotateBy):
    return chr((ord(char)+rotateBy)%126+1)

def caesarDecrypt(char, rotateBy):
    return chr((ord(char)-rotateBy-1)%126)

def encrypt(inString, password):
    outString = ""
    index = 0
    for ch in inString:
        ch = caesarEncrypt(ch, ord(password[index]))
        outString = outString + ch
        index = (index+1)%len(password)
    return outString

def decrypt(inString, password):
    outString = ""
    index = 0
    for ch in inString:
        ch = caesarDecrypt(ch, ord(password[index]))
        outString = outString + ch
        index = (index+1)%len(password)
    return outString

def encrypt_command():
    global textWidget
    password = tkSimpleDialog.askstring("Password", "Please Enter your Password")
    if password != None:
        contents = textWidget.get("1.0", ScrolledText.END)[:-1]
        encrypted = encrypt(contents, password)
        textWidget.delete("1.0", ScrolledText.END)
        textWidget.insert(ScrolledText.END, encrypted)

def decrypt_command():
    global textWidget
    password = tkSimpleDialog.askstring("Password", "Please Enter your Password")
    if password != None:
        contents = textWidget.get("1.0", ScrolledText.END)[:-1]
        encrypted = decrypt(contents, password)
        textWidget.delete("1.0", ScrolledText.END)
        textWidget.insert(ScrolledText.END, encrypted)

if __name__ == "__main__":
    root = Tkinter.Tk()
    textWidget = ScrolledText.ScrolledText(root, width=80, height=50)
    textWidget.pack()

    menuBar = Tkinter.Menu(root, tearoff=0)
    fileMenu = Tkinter.Menu(menuBar, tearoff=0)
    fileMenu.add_command(label="Open", command=open_command)
    fileMenu.add_command(label="Save", command=save_command)
    fileMenu.add_separator()
    fileMenu.add_command(label="Quit", command=exit_program)
    menuBar.add_cascade(label="File", menu=fileMenu)
    encryptMenu = Tkinter.Menu(menuBar, tearoff=0)
    encryptMenu.add_command(label="Encrypt", command=encrypt_command)
    encryptMenu.add_command(label="Decrypt", command=decrypt_command)
    menuBar.add_cascade(label="Encrypt", menu=encryptMenu)

    root.config(menu=menuBar)
    
    root.mainloop()
\end{python}

\section{Glossary}

\begin{description}
\item[cipher:] An encryption algorithm.
\item[ASCII:] American Standard Code for Information Interchange. A
common representation of text characters.
\item[Unicode:] A more modern representation of text characters that
allows for a much larger range of characters and includes characters
from many different languages.
\item[modulo arithmetic:] arithmetic performed on a limited range of
numbers. 
\end{description}

\newpage
\section{Laboratory Exercises}

\begin{enumerate}
\item \label{lab-24-1} A Caesar cipher is trivially easy to break as
there are only $N$ 
different ways of encrypting a given text, where $N$ is the number of
characters in the alphabet. From the Blackboard page, download
\myurl{caesar\_crypt.txt} and save it to your home
directory. \myurl{caesar\_crypt.txt} has been encrypted using the
\pythoninline{caesarEncrypt} function. Using
the program above as a starting point, write a function that tests
each possible \pythoninline{rotateBy} value to decrypt the text.

\item A Caesar cipher is the simplest of substitution ciphers. A more
general substitution cipher allows any mapping from input character to
output character, not just a rotation. The number of different
possible mappings is $N \times (N-1) \times (N-2) \times ... 1$. You
can see this is true by noting that there are $N$ possible
substitutions for the first character, $N-1$ for the second character
and so on. As you probably know, this function is called factorial. 
Implement a factorial function and work out the number of different
possible mappings when $N=126$. Make sure you remember to include
doctests to test your function.

Do you think the method you used in Question \ref{lab-24-1} will work
for this case?

\item One way of implementing a substitution cipher is to use a
dictionary that maps from an input character randomly to an output
character. The following code can be used to construct the dictionary:

\begin{minipage}{\textwidth}
\begin{python}
import random

keys = range(1,127)
values = range(1,127)
random.seed("SomePassword")
random.shuffle(values)

encrypt = dict()
decrypt = dict()
for (i,j) in zip(keys,values):
    encrypt[chr(i)] = chr(j)
    decrypt[chr(j)] = chr(i)
\end{python}
\end{minipage}

Using the above code, or code of your own design, incorporate a random
substitution cipher into the encryption program.

\item The statement \pythoninline{random.seed("SomePassword")} seeds
the random number generator so that \pythoninline{random.shuffle}
produces the same shuffle each time the program is run. I have used a
string constant as a seed in the code for the previous question, but
this means that all documents encrypted with a substitution cipher
will use the same substitution. Modify your answer to the previous
question to allow the user to enter a password for specifying the seed
value.

\end{enumerate}

\section*{Extension Exercises}
\begin{enumerate}
\item Substitution ciphers can be broken using frequency analysis.
Frequency analysis examines the number of times each character occurs
in the encrypted text and makes guesses regarding the identity of the
character based on its relative frequency. For example, ``e'' is the
most common letter in English prose, therefore we would guess that the
most common character in the encrypted text is ``e''. For more details
about frequency analysis, have a look at:
\url{http://en.wikipedia.org/wiki/Frequency_analysis}. From the
Blackboard page, download the cipher text
\myurl{substitution\_encrypt.txt} and see if you can decrypt it
using frequency analysis.
\end{enumerate}

