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 finishedThe 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
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
(username, nonce1) Message1: Client -----------------------------------> Server (kAuth{nonce1}, nonce2) Message2: Client <----------------------------------- Server (kAuth{nonce2}, kAuth{kSession}) Message3: Client -----------------------------------> ServerHere 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 -----------------------------------> ServerNote that the server is structured so that multiple clients can connect simultaneously.
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.
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.
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