In this assignment, you'll add functionality to the code you wrote for Projects 1 and 2 to reach the goal of implementing a secure facility for client-server communication across the Internet.
As before, we will give you some of the code you need, and we'll ask you to provide certain functions missing from the code we provide via chisubmit. As before, you must not use any crypto libraries; the only primitives you may use are the ones we gave you and ones you implemented from scratch yourself.
In this assignment, you will implement a secure channel abstraction
that can be used by two programs, a client and a server, to
communicate across the network, with the confidentiality and integrity
of messages guaranteed. We have given you a class
InsecureChannel
which implements a channel that works but is not secure: everything is
sent in unprotected cleartext. We have also given you stubbed-out code
for a class
SecureChannel
that extends
InsecureChannel
and (once you have modified it) will protect security and
confidentiality.
IMPORTANT: For this assignment, we will also REQUIRE a README file. In the file, you should describe your setup and your threat model: What are you doing? How would a user of the classes you've written use them? And what security properties (against what sort of adversary) should they expect to get if they use them correctly? You should write these items in addition to any documentation you would normally put in comments or a README. Your README should be short — a few paragraphs at most.
SecureChannel. Your SecureChannel class should implement the following API:
public class SecureChannel extends InsecureChannel { public SecureChannel(InputStream inStr, OutputStream outStr, PRGen rand, boolean iAmServer, RSAKey serverKey) throws IOException public void sendMessage(byte[] message) throws IOException public byte[] receiveMessage() throws IOException }
The constructor will contain the vast majority of your code. Its role
is to set up the secure channel such that the
sendMessage
and
receiveMessage
methods can do their jobs. These methods should provide authenticated
encryption for the messages that pass over the channel, ensuring that
messages arrive at the receiving end in the same order that they were
sent on the sending end. Furthermore, when the client is setting up
its channel, it should also authenticate the server's identity, and
should take whatever steps are necessary to detect any
man-in-the-middle. If one of the two parties (server or client)
detects a potential security problem during channel construction, that
party should close the channel by calling
close
.
The underlying InsecureChannel
will normally deliver messages in the
same order they were sent. But note that an adversary might try to
reorder messages.
receiveMessage
should return null
if an invalid or out-of-order message shows up.
Compiling and running. This assignment makes use of the classes you
implemented in Projects 1 and 2. To avoid doubly penalizing you for any
mistakes you may have made in the previous assignments, we are
providing you with a compiled reference implementation of Projects 1 and 2 in
project1.jar
and project2.jar
. This assignment also
makes use of Java assertions. To ensure that you use the appropriate JAR files
and enable assertions, please compile the code with the following command on Linux and Mac:
javac -cp project1.jar:project2.jar:. [.java files]and this one on Windows (note the semicolons instead of the colons):
javac -cp "project1.jar;project2.jar;." [.java files]and run it with this on Linux and Mac:
java -ea -cp project1.jar:project2.jar:. [main class]and this on Windows (note the semicolons instead of the colons):
java -ea -cp "project1.jar;project2.jar;." [main class]
As before, we will be testing your code with Java 8, and so please use that
version when compiling and running your implementation. You can check
your Java version by typing
javac -version
and verifying that the version begins with
1.8.0_
. (If you only have the
java
command but not the
javac
command, you have the Java runtime, but you need to install the Java
Development Kit.) You can download the Java Development Kit here.
Support code. We have provided a few classes and methods to facilitate testing:
SecureChannelUtils
provides a few methods for printing out formatted byte arrays.ChannelTest
provides a demonstration that InsecureChannel
works correctly.SecureChannelTest
enables you to test whether your SecureChannel
is working.
It does NOT test the channel's security properties, however.InsecureChannel
(and therefore its subclass SecureChannel
) has two methods that are useful for debugging.
Passing true
to setDebugMode
causes the channel to print the contents of every message sent and received.
setNumBytesToEcho
changes the number of bytes of each message printed in debug mode. The default is to
print all the bytes.Assignment Tips and Tricks.
ChannelTest
, which will
provide you with a better understanding of how InsecureChannel
and SecureChannel
are intended to be used. In
particular, two instances of InsecureChannel
will be
created (one for the server-to-client channel and one for the client-to-server
channel), each of which connects up two data streams (one
input and one output data stream). Messages are sent through the
channel using the sendMessage
method, and whenever a
message is sent via a channel, it stays there until a corresponding receiveMessage
call is made. Luckily for you, you won't need to think about InputStreams
or OutputStreams
at all. That is all taken care of in InscureChannel
and in the main function of the ChannelTests
. You also shouldn't have to deal with
Runnable
classes and Threads
.
SecureChannelTest
to get a
feeling for how the SecureChannel
instantiations differ.
SecureChannelTest
, if a thread calls readMessage
and there is no message available, it will wait until a message
becomes available.
super.methodName
.
For example, SecureChannel
can use InsecureChannel
's version of sendMessage
via super.sendMessage
.PRGen
, you can use other methods of its superclass
java.util.Random because they're
actually implemented in terms of next
. For example, PRGen.nextBytes
might be useful.A few words about grading. As before, some of your grade will be based on whether your code passes certain automated tests. But, as stated previously, the security of your implementation ultimately depends on its design and cannot be verified by testing alone. An implementation that compiles, runs, and appears to work may in fact be insecure. As a result, manual inspection of your design will determine a large part of your grade.
Adapted from an assignment copyright 1998–2014, Edward W. Felten. Used with permission.