Project 2 : Cryptographic Protocols
CIS/TCOM 551


Due: March 14, 2006

Description

Besides writing the blame service of Project 1, Feckless C. Coder, PhD has also written a handy "authenticated echo" system, which he intends to eventually develop into a full-blown encrypted chat service that will replace AIM and earn him a gazillion dollars. This software is also written entirely in Java, so it is not susceptible to buffer overflows. Part of Feckless's sales pitch is that his software uses advanced Rijndael cryptographic operations to authenticate the client and server to each other and to encrypt the echo traffic (so you know it must be secure).

The service consists of three (cleverly named) pieces of software: KeyGen, a tool for generating the Rijndael keys shared between clients and the server, Server, the echo server to which clients can connect and send encrypted messages, and Client, the software that authenticates a user to the server and accepts their input.

Here is an example transcript of installing the software, generating a shared key for user Alice and starting the echo server:

% tar -xzf project2.tar.gz
% cd project2
% setenv CLASSPATH "/home1/s/stevez/cis551/project2:/home1/s/stevez/cis551/project2/cryptix32.jar"
% make all
javac  Client.java
javac  KeyGen.java
javac  Server.java
% java KeyGen alice rij
% java Server 21210
----------------------------------------
  Echo server is running on port 21210
----------------------------------------
# authenticating user: alice
# sending Message 2...
# authentication succeeded.
alice: Come here, Watson, I want you.
# alice's session finished
The server prints diagnostic messages preceded by # and echoes messages sent by clients by prefixing them with their username. For example, this transcript shows that a client authenticated as user Alice and sent the message "Come here, Watson, I want you.". Feckless's intention is that to authenticate as shown above, the client must have access to the file alice.shared, which contains the Rijndael key generated by KeyGen. For example, the above transcript was generated by running the following commands in another terminal (assuming that the CLASSPATH environment variable is set correctly for this terminal too):
% cd project2
% java Client alice localhost 21210
# sending Message 1...
# received Message 2...
# nonce check succeeded...
# authentication complete.
Come here, Watson, I want you.
done

Details

  1. The source code for the authenticated echo system can be found in this file project2.tar.gz
  2. The CLASSPATH environment variable should contain the paths to the project2 directory (where ever you untar the file) and to the project2/cryptix32.jar file. For example, under bash this might be accomplished by doing:
    setenv CLASSPATH "/home1/s/stevez/cis551/project2:/home1/s/stevez/cis551/project2/cryptix32.jar"
    
    It may be convenient for you to add this to your .login or .bashrc files
  3. The most convenient host address for you to try running the server on is localhost as in the example above (although the software should work for remote machines as well). You should be able to specify either an actual IP address (e.g. 195.50.2.123) or a hostname (e.g. zero.cis.upenn.edu).
  4. Under Linux (i.e. eniac-l) port numbers 20300-21589 are unassigned, and so they make goot choices for this project. You may get a java.net.BindException: Address already in use if you try to run your server on the same port as another program (or instance of the server).
  5. Feckless has left important details about key management for future work -- in particular, the Server and Client software expect the shared keys they need to be stored in the linux filesystem following the naming convention .shared. One convenient way to achieve this is to run the Server and Client programs from the same directory. (You can run them remotely, but then you have to copy the shared keys to the appropriate machines.)

Authentication and Key Exchange

Feckless's authenticated echo server uses a challenge-response protocol to first authenticate the user to the server and the server to the user. Since Feckless knows that reusing shared keys for multiple purposes is a potential security hole, the protocol also establishes a fresh session key each time a user logs in. The session key is used to encrypt subsequent messages echoed to the server. The authentication and key exchange protocol consists of three messages:
                             (username, nonce1)
Message1:   Client  -----------------------------------> Server

                           (kAuth{nonce1}, nonce2)
Message2:   Client  <----------------------------------- Server

                      (kAuth{nonce2}, kAuth{kSession})
Message3:   Client  -----------------------------------> Server

Here kAuth is the key shared between the principal identified by username and the Server. For example, username might be alice and kAuth would be the key stored in alice.shared. The Server uses the username field of the first message to load the appropriate key from disk. kSession is generated by the client for each run of the protocol. After this protocol completes successfully (and assuming that the nonces verify correctly), the Client and Server share the key kSession that can be used to send further encrypted traffic following this simple protocol:
                               kSession{data}
Message4:   Client  -----------------------------------> Server
Note that the server is structured so that multiple clients can connect simultaneously.

Deliverables

Despite his best efforts, Feckless's echo server is not at all secure. Your goal for this project is to (1) demonstrate the (major) vulnerabilities and (2) fix them.
  1. Create a program called EvilClient. This program should behave like a legitimate Client program (including all command-line arguments) that allows a user to authenticate to the server and transmit encrypted messages except EvilClient should not need access to the user's shared key. This program should consist of two files EvilClient.java and EvilClientSession.java. You should not need to modify any other code (we will test your EvilClient against our own Server). The README documentation you turn in with your project should include a sequence of steps that the grader can use to convince himself that your EvilClient works.
  2. The problems with the authenticated echo server stem from two sources: first, the protocol is badly designed, and, second, the code implementing the protocol is of poor quality (mostly due to the fact that Feckless cut and paste his code from examples without really knowing how they worked). In fact, fixing either of these problems independently would rule out many attacks like the EvilClient, but fixing both is better. The second part of the project is to fix both of these problems. That is, design and implement a correct key exchange protocol and improve on Feckless's code. To understand in what ways Feckless's code is poor, you can look at what properties of the software your implemenation of EvilClient exploits -- had Feckless followed better software engineering practices, it would be much harder (if not impossible) to implement EvilClient (even without using a better protocol!).

    Note that there may be other vulnerabilities of the system that are not exploited by your implementation of EvilClient. If you find such vulnerabilities, you should fix them.

    Your write up for the project should describe the new protocol you implemented, what changes you made to improve the system's code quality, and document any other vulnerabilities (and their fixes!) you found during this process. How do you know that the protocol is secure?

    For this part of the project, you may change any of the source files provided except Crypto.java, Disk.java, and KeyGen.java (be sure to document what changes you have made!). To facilitate testing do not change the names or command-line arguments of Server and Client. You should not need to use the cryptix32.jar module directly -- all the functionality you need should be in Crypto.java; see the comments there.

CIS 551 - Project 2 Submission Guidelines

Send your project submission to cis551staff@seas.upenn.edu by midnight on the due date.

Commenting your code

Make sure your code is well commented. This does not mean you need to explain every line - unnecessary comments on obvious operations actually hurt readability - but you should provide a high-level overview of the reasoning behind any non-trivial method that you write, and behind any additional classes you might create. If you feel that a particular statement or block is particularly important and that this importance might be missed by the reader, leave a brief comment there as well.

Normally you should remove any commented-out code from the final version of a project. If you strongly feel that some some of this code will help the reader understand what you've written, move the commented-out code into an explanatory comment that shows why it is wrong and why your revised version is correct.

Comments are there to help the reader understand what you wrote and why you wrote it that way. They should not be required reading for anyone who wishes to execute your program, and documentation unrelated to your source code should be placed somewhere else.

Files to submit

Your submission should include all of your source code and documentation. It should not include any object code - in this case, Java .class files.

Submit a compressed tar file that expands into a directory matching your username. For example, if your username is adent and you've been placing your files in ~/cis551/project2, would could run the following commands:

adent@minus:~/cis551/project2$ make clean
adent@minus:~/cis551/project2$ cd ..
adent@minus:~/cis551$ mv project2 adent
adent@minus:~/cis551$ tar czf adent.tar.gz adent

You would then submit the file adent.tar.gz.

You should include a README file (plain text) that explains, briefly, the purpose of each file you have submitted. It should also provide any information required to compile or run your program, as well as your contact information. Any other documentation you submit should also be in plain text format unless it requires complex formatting, in which case you should submit a PDF file. Do not submit a Microsoft Word document.

You should also include a Makefile (called Makefile) which can be used to automatically build your project. A Makefile should also be helpful while you're working; if properly set up, you will be able to rebuild any .class file by typing make filename, and make will be certain to rebuild any other .class files that are relevant and that may have changed. This lets you avoid recompiling your entire project while eliminating strange bugs caused by out of date files.

The project source code contains a working makefile (based on the simple example below).

More information on Makefiles can be found in The GNU Make Manual; the following simple example should help you get started. It assumes that we have three source files, Foo.java, Bar.java, and Baz.java. The class Foo makes reference to both Bar and Baz, but neither of those classes references either the other or Foo.

# A good Makefile begins with variable declarations that capture important
# parts of the project.  In this case we have a list of class files that
# comprise the program, as well as the name and command line arguments for
# the Java compiler.

# If more classes are added to the program, we can list them here to ensure
# that they will be compiled.
CLASSES = Foo.class Bar.class Baz.class

# Putting the compiler and compiler options in variables lets us change them
# later and have these changes apply to every file.
JAVAC = javac
JAVAOPTS =

# The remainder of a makefile consists of rules of the form
#
#  target: prerequisites
# 	command
#
# If you run the command "make target", make will first check that all
# the prerequisites are present and up to date, then run the command.
# If prerequisites are missing or out of date, make will look for rules
# with those prerequisites as their targets.
#
# You MUST put a tab before the command; a sequence of spaces will not
# work.

# Some targets do not correspond to actual files; you can declare that
# they are "phony" like this.
.PHONY: all clean

# The first target in the file is selected automatically if you call
# make with no argument.  In this case it will compile all the classes
# that comprise our program.
all: $(CLASSES)

# A "clean" target allows us to quickly delete all automatically generated
# files.  This should be run right before you submit your project, and may
# be helpful any time you would like to quickly get rid of old files.  It
# uses a $(RM) variable that we did not define; this is fine, however, as
# make includes many predefined variables.
clean:
	$(RM) *.class

# This rule tells us that class Foo depends on classes Bar and Baz, and
# thus Bar and Baz should be built first.  Every class depends on its
# source file.  The special variable $< refers to the first prerequisite,
# which is generally the source file.
Foo.class: Foo.java Bar.class Baz.class
	$(JAVAC) $(JAVAOPTS) $<

# Bar and Baz have no other dependencies, and we imagine that this will be
# the case with most other source files that we add to our program.  The
# following target establishes a pattern, saying that any .class file can
# be built from its .java file.  This pattern will apply whenever we do
# not give a specific rule, so we can save those for when we have
# dependencies.
%.class: %.java
	$(JAVAC) $(JAVAOPTS) $<
Last Revised: 15 February 2006