CIS 5357 - Network Security -

Florida State University - Fall 2005

Instructor: Breno de Medeiros



Homework assignment 3 (100 pts = 2 previous assignments):



Goal of Assignment: 

Implement the MTI/A0 key agreement protocol (authenticated Diffie-Hellman Key Exchange)

Due date:  11/09/2005

References:
   
Motivation:


Recipe for Success:

Recipe(s) for Failure:

Grading of assignment:

  1. MTI/A0 implemented correctly:  50% of the grade.
  2. If  SecureMessages implemented correctly: 40% of grade
  3. Documentation: 10%


Specifications:

You should modify the TCPEchoClient and TCPEchoServer Classes in the submission.Demo subpackage of Simnet.
The modified classes should be called TCPDHClient and TCPDHServer.

In order to generate DH public key parameters, use the classes org.bouncycastle.crypto.generators.DHParametersGenerator an org.bouncycastle.crypto.params.DHParameters;

DHParametersGenerator DHgen = new DHParametersGenerator();
SecureRandom srand = new SecureRandom();
DHgen.init(2048,80,srand);
DHParameters DHparam = DHgen.generateParameters();
try {
       OutputStream fileout = new FileOutputStream("DHparams.out");
       ObjectOutputStream oout =  new ObjectOutputStream(fileout);
       DHParametersWrapper dhwrap = new DHParametersWrapper();
       dhwrap.setDHParameters(DHparam);
       oout.writeObject(dhwrap);
       oout.close();
} catch(IOException e) {
    e.printStackTrace();
}

Execute this code immediately to generate your params once.  Make a backup copy of your params.   Generating the params the first time may take hours!  Having the same parameters as another student is considered cheating.  (The probability that you will generate the same params as somebody else by chance is probably smaller than an elephant will suddenly materialize on your living room by quantum effects.)  This parameter is used by both Client and Server.

Once you have generated the DH parameters, you can generate your private key (a securely random BigInteger numBits long, where numBits is the bitlength of q. You can call
BigInteger q = DHparam.getQ();
 method on DHparam to get the value q, and compute its bitlength as q.bitLength(); 
Once a client and server keys have been generated they can be saved as DHPublicKeyParameters.  You should also save your private keys separately (as BigIntegers)


You should proceed the same way to obtain the values used in the MTI/A0 algorithm.

It is required that the TCPDHClient be invoked when one must "connect" to a listening server (an instance of
TCPDHServer).

After the completion of the 3-way TCP handshake, the TCPDHClient must send a message containing a single
object that implements the following interface.

===================================MTI/A0 implementation

public interface CryptographicAuthenticationMessage {

    public String getSenderName(); // returns the name of the client sending this message
    public Object getAlgorithmSpecs();
                                                       // For this protocol, the return value should be of type
                                                        //
org.bouncycastle.crypto.params.DHPublicKeyParameters;
                                                        // Since this class should be serializable, you will need to keep your DHPublicKeyParameters
                                                        //using a DHPublicKeyParametersWrapper instance.
    public java.sql.Timestamp getTimestamp();           // The time this message was created
    public Object[] getArguments();  // The other arguments of this protocol.
    public String getSessionID(); // In this protocol, it is computed as the concatenation of Sender name, the special
                                          // character sequence '::' followed by the receiver's name, another '::' and the
                                           // string obtained by calling the method toString() in the Timestamp.

}

The server, at this point, should:

1) Check that it knows the Sender by name
2) Check that the public key part of the DHPublicKeyParameters returned by the getAlgorithmSpecs() corresponds to the sender.  (You should assume a few associations of public keys and names).
3) Check that the timestamp is not too different from the current time at the server (acceptable clock skew of at most 5 seconds).
4) Check that the sessionID is computed correctly from the Sender's name, the server's name, and the sender's timestamp.
5) Read the value returned by getArguments().

If all steps succeed, the server continues with the protocol.  Otherwise, it should ignore the message. (And time out if no valid message is received within 30 seconds).

Note that the returned array by getArguments() should contain a single object, OF TYPE BigInteger, the value A = ga mod p which specified as a random value in a DH key exchange.

The response by the server is of the same type (
CryptographicAuthenticationMessage), with the appropriate changes:

1) The sender name is the server's name
2) The DHPublicKeyParameters are the server's parameters
3) The timestamp is that of the server
4) The sessionID is THE SAME AS THE VALUE SENT BY THE CLIENT.
5) getArguments() should return a single value OF TYPE BigInteger, namely B = gb mod p which is the random value in a DH Key Exchange.

The shared pre-key should be computed as in the MTI/A0 key exchange, i.e., as pre-K = gax + by mod p, where x is the private key of the server, and y the private key of the client.  More specifically,

i.)  Client computes pre-key pre-K = (Public key of server)a Bmod p.

ii.) Server computes pre-key pre-K = (Public key of client)b Ax mod p.

The server and client then initialize a SecureRandom generator, set the seed to be the value of the pre-key (converted to bytes using toByteArray()), and compute a 1280-bit output.  The first 512 bits will be used as  encryption key (Kenc0,Kenc1) for AES-256.  The second 512 bits will be used as authentication keys (Kauth0,Kauth1) for HMAC-SHA256.  The next 128-bits are IV0, and the following 128-bits are IV1.


============================================End of MTI/A0 implementation

Now, each party must prove that they have computed the same pre-key.  The client starts, sending a message of type

public interface SecureMessage {

    public byte[] getEncrypted();
    public byte[] getAuthenticator();

}

The bytes returned by getEncrypted are computed as follows:  First compute a String contained the concatenation of

1) The number '0'
2) '::'
3) SessionID
5) '::'
5) A.toString() // A is the random challenge by the client
6) '::'
7) B.toString() // B is the random challenge by the server


Then convert the above String to a byteArray, and encrypt it using AES-CBC with PKCS7 padding and with IV = IV0 and key Kenc0.  The output is the value of getEncrypted();

The value returned by getAuthenticator() should be the HMAC-SHA256 digest of the byte array returned, getEncrypted() computed under the authentication key Kauth0.

The server must first verify if the authenticator is computed correctly from the encrypted value.  Then it should decrypt and check that the contents are as expected.  It should reply with a message also of the type SecureMessage.  The only difference is that
the value in (1) should be '1',  the IV used in encryption should be IV1, and the keys should by Kenc1 and Kauth1.

After this, the client should wait for messages of the type "echo X", where X is a string, and transmit it as a SecureMessage.  Here, the String 'X' is just converted to byteArray and encrypted (without re-setting the cipher in AES-CBC mode, still with IV = IV0), as well as authenticated---here re-setting the MAC each time.
The Server should verify the MAC, decrypt, re-encrypt the message using the IV = IV1, Kenc1, and authenticate it with Kauth1.
The Client must verify and decrypt the Server messages, printing the result on screen as an echoed value.  If the authentication fails, the client prints an error.

Every time a server of client detects an error, it should ignore and continue waiting for the next message.  If idle for more than 30 seconds (including erroneous messages), the client and/or server should close the connection using a TPC RST packet.


Deliverables:

1) TCPDHClient and TCPDHServer classes, and auxiliary classes.

2) Two serialized objects of type DHPublicKeyParametersWrapper, in files named serverKey.public and clientKey.public;  (use ObjectOutputStream to write these)

3) Two serialized objects of type BigInteger (the private keys), in files named serverKey.private and clientKey.private.

4) A file containing the server and client names.