In this assignment, you will add functionality to the code you wrote for Assignments 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 will ask you to provide certain functions missing from the code we provide. As before, you must not use any cryptographic libraries; the only primitives you may use are the ones we gave you, and ones you implemented from scratch yourself. Your solution will build on the functionality that you implemented for Assignment 2, but we will test your solution with our own implementation of the Assignment 2 functionality. Your solution must work correctly when we do this — this shouldn’t be a problem as long as you respect the API boundaries between the different classes we have given you. To help you mimic the testing setup that we will use, we are providing a pre-compiled JAR file (library) containing our reference solution to Assignment 2. We recommend that you use this instead of your own solution to Assignment 2.
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 a network, with the confidentiality and integrity of messages guaranteed. We have given you a class InsecureChannel that implements a channel that works but is not secure: everything is sent in unprotected cleartext. We have also given you stubbed-out code for the SecureChannel class that extends InsecureChannel and (once you have modified it) will protect security and confidentiality.
To facilitate the testing process, we have provided the following files:
Util432s.java - provides a few methods used by the other testing files (feel free to use these methods for debugging).ChannelTest.java - provides a demonstration that the InsecureChannel class works correctlySecureChannelTest.java - used to test your SecureChannel class (once implemented). Note that this class does NOT test security properties, instead testing only basic functionality. Also, note the commented out lines that give an example of how you can use Util432s for debugging.InsecureChannel.java.debug - provides a special version of InsecureChannel and provides the ability to echo channel transmissions to the screen. To use this class, simply rename the file InsecureChannel.java and place it in the same directory as SecureChannel.java.Your AuthEncryptor class should implement the following API:
public class AuthEncryptor {
public AuthEncryptor(byte[] key)
public byte[] authEncrypt(byte[] in, byte[] nonce, boolean includeNonce)
}
This class is used to perform authenticated encryption on values. Authenticated encryption protects the confidentiality of a value, so that the only way to recover the initial value is to decrypt the value using the same key and nonce that was used to encrypt it. At the same time, authenticated encryption protects the integrity of a value, so that a party possessing the same key and nonce (that were used to authenticate it) can verify that nobody has tampered with the value.
Code that uses AuthEncryptor will be required to pass in a different nonce for every call to the authEncrypt method. The AuthEncryptor class is not required to detect violations of this rule; it is the responsibility of the code that uses AuthEncryptor to avoid re-using a nonce with the same AuthEncryptor instance.
includeNonce is true, then the nonce should be included (in plaintext form) in the output of authEncrypt. If includeNonce is false, then the nonce should still be used in calculating the output, but the nonce itself should not be copied into the output. (Presumably the party who will decrypt the message already knows what the nonce will be.)
Your AuthDecryptor class should implement the following API:
public class AuthDecryptor {
public AuthDecryptor(byte[] key)
public byte[] authDecrypt(byte[] in)
public byte[] authDecrypt(byte[] in, byte[] nonce)
}
The value passed as in will normally have been created by calling authEncrypt() with the same nonce in an AuthEncryptor that was initialized with the same key as this AuthDecryptor.
If the integrity of the input value cannot be verified (that is, if the input value could not have been created by calling authEncrypt() with the same nonce in an AuthEncryptor that was initialized with the same key as this AuthDecryptor), then this method returns null. Otherwise it returns a newly allocated byte-array containing the plaintext value that was originally passed to authEncrypt().
If the nonce is included in the message, then the message should be processed with the authDecrypt(byte[] in) method. Otherwise, the nonce should be provided along with the ciphertext to authDecrypt(byte[] in, byte[] nonce).
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 send 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(). To ensure foward secrecy, the close() method must delete any secret values associated with the channel. You can assume the serverKey (public key) passed to the constructor of SecureChannel on the client side of the communication is verified externally in some way (for example via a trusted certificate).
The underlying InsecureChannel will normally deliver messages in the same order they were sent. But note that an adversary might try to reorder messages. The receiveMessage method should return null if an invalid or out-of-order message shows up.
ChannelTest.java, 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 → client channel and one for the client → 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 will not need to think about InputStreams or OutputStreams at all. That is all taken of in InsecureChannel.java and in the main function of the ChannelTests.InputStreams and OutputStreams, don’t worry, you won’t be dealing with them very closely. The same goes for runnable classes and threads.InsecureChannel.java.debug over InsecureChannel.java and running ChannelTest, which will let you see the raw traffic being sent over the channel.SecureChannelTest.java to get a feeling for how the SecureChannel instantiations differ.Report.txt file. This report should succinctly demonstrate that you have considered both the threats against your implementation and the specific techniques you use to defend against them. One way to format this is to describe a threat in a sentence or two, followed by a sentence or two that explains how your implementation defends against it; repeating this format for each threat.SecureChannelTest, if a thread calls readMessage and there is no message available, it will wait until a message becomes available.Submit your files to the Gradescope:
Report.txt Threat model and Mitigation Description (see Getting Started for requirements).AuthEncryptor.java - Source code file containing your implementation of the AuthEncryptor class.AuthDecryptor.java - Source code file containing your implementation of the AuthDecryptor class.SecureChannel.java - Source code file containing your implementation of the SecureChannel class.