//SecureTCPClient.java

import java.io.*;
import java.net.*;
import krb5.lib.*;

class SecureTCPClient {

	public static void main(String args[]) throws UnknownHostException {
		String principal = "sanfilip@drdoom.osf.org";
		StringBuffer password = new StringBuffer("somewha0");
		String kdc = "drdoom.osf.org";
		String service = "khttp/drdoom.osf.org@drdoom.osf.org";
		InetAddress address = InetAddress.getLocalHost();
		int port = 8891;
		TCPClient client = null;

		//generate a specific subSessionKey from a character string
		//String subKeyString = "sdfsdffg";
		//byte[] subKeyData = new byte[subKeyString.length()];
		//subKeyString.getBytes(0, subKeyString.length(), subKeyData, 0);
		//EncryptionKey subSessionKey = new EncryptionKey(subKeyData);

		//or...

		//specify no subSessionKey
		EncryptionKey subSessionKey = null;

		try {

			//as_req

			KrbAsReq as_req = new KrbAsReq(
				password, //for pre-authentication
				new KDCOptions(),
				new PrincipalName(principal),
				null, //PrincipalName sname
				null, //KerberosTime from
				null, //KerberosTime till
				null, //KerberosTime rtime
				null, //int[] eTypes
				null, //HostAddresses addresses
				null //Ticket[] additionalTickets
			);

			System.out.println("send as_req");

			as_req.send(kdc);
			KrbAsRep as_rep = as_req.getKrbAsRep(password);

			System.out.println("received as_rep");

			//tgs_req

			KrbTgsReq tgs_req = new KrbTgsReq(
				new KDCOptions(),
				as_rep.creds(),
				new ServiceName(service),
				null, //KerberosTime from
				null, //KerberosTime till
				null, //KerberosTime rtime
				null, //int[] eTypes
				null, //HostAddresses addresses
				null, //AuthorizationData authorizationData
				null, //Ticket[] additionalTickets
				null //EncryptionKey subSessionKey
			);

			System.out.println("send tgs_req");

			tgs_req.send(kdc);
			KrbTgsRep tgs_rep = tgs_req.getKrbTgsRep(as_rep.creds());

			System.out.println("received tgs_rep");
			System.out.println();

			client = new TCPClient(address, port);

			String str = " 01234567ABCDEFGHello; this is a secure message!";
			byte[] userData = new byte[str.length()];
			str.getBytes(0, str.length(), userData, 0);

			LocalSeqNumber seqNumber = new LocalSeqNumber();

			KrbApReq ap_req = new KrbApReq(
				new APOptions(Krb5.AP_OPTS_MUTUAL_REQUIRED),
				tgs_rep.creds(),
				null, //Checksum cksum
				subSessionKey,
				seqNumber,
				null  //AuthorizationData authzData
			);

			System.out.println("send ap_req");

			client.send(ap_req.msg());
			byte[] ibuf = client.receive();

			System.out.println("received ap_rep");
			
			KrbApRep ap_rep = new KrbApRep(
				ibuf,
				tgs_rep.creds()
			);
			ap_rep.authenticate(ap_req);
			if (ap_rep.getSubKey() != null)
				subSessionKey = ap_rep.getSubKey();

			System.out.println("authenticated");
			System.out.println("server=\"" + tgs_rep.creds().server + "\"");
			System.out.println();

			do {

				System.out.println("userData=\"" + new String(userData, 0) + "\"");

				KrbMkPriv krb_priv = new KrbMkPriv(
					userData,
					tgs_rep.creds(),
					subSessionKey,
					new KerberosTime(KerberosTime.NOW),
					seqNumber,
					null, //new HostAddress(),
					null //new HostAddress(InetAddress.getLocalHost())
				);

				System.out.println("send");

				client.send(krb_priv.msg());
				ibuf = client.receive();

				System.out.println("received");
				
				KrbRdPriv krb_priv_reply = new KrbRdPriv(
					ibuf,
					tgs_rep.creds(),
					subSessionKey,
					seqNumber,
					null, //new HostAddress(client.getInetAddress()),
					null, //new HostAddress(),
					true, //boolean timestampRequired
					true //boolean seqNumberRequired
				);

				System.out.println("decrypted");

				byte[] replyData = krb_priv_reply.data();

				System.out.println("replyData=\"" + new String(replyData, 0) + "\"");
				System.out.println();

				//why wait..
				//try {
				//	Thread.currentThread().sleep(1000);
				//} catch (InterruptedException e) { }

			}
			while (true);

		}
		catch (KrbException e) {
			e.printStackTrace();
			System.out.println(e.krbErrorMessage());
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			try {
				if (client != null)
					client.close();
			}
			catch (IOException e) {
			}
		}		

		System.out.println("ok");
	}
}