148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/*
248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * Please refer to the LICENSE.txt for licensing details.
448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */
548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpackage ch.ethz.ssh2.transport;
648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.IOException;
848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.InputStream;
948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.io.OutputStream;
1048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport java.security.SecureRandom;
1148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
1248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.cipher.BlockCipher;
1348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.cipher.CipherInputStream;
1448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.cipher.CipherOutputStream;
1548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.cipher.NullCipher;
1648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.crypto.digest.MAC;
1748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.log.Logger;
1848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodimport ch.ethz.ssh2.packets.Packets;
1948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
2048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood/**
2148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * TransportConnection.
2248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood *
2348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @author Christian Plattner
2448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood * @version $Id: TransportConnection.java 41 2011-06-02 10:36:41Z dkocher@sudo.ch $
2548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood */
2648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwoodpublic class TransportConnection
2748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood{
2848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	private static final Logger log = Logger.getLogger(TransportConnection.class);
2948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int send_seq_number = 0;
3148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int recv_seq_number = 0;
3348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	CipherInputStream cis;
3548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	CipherOutputStream cos;
3748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
3848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	boolean useRandomPadding = false;
3948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	/* Depends on current MAC and CIPHER */
4148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	MAC send_mac;
4348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	byte[] send_mac_buffer;
4548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int send_padd_blocksize = 8;
4748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
4848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	MAC recv_mac;
4948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	byte[] recv_mac_buffer;
5148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	byte[] recv_mac_buffer_cmp;
5348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	int recv_padd_blocksize = 8;
5548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	/* won't change */
5748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
5848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	final byte[] send_padding_buffer = new byte[256];
5948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	final byte[] send_packet_header_buffer = new byte[5];
6148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	final byte[] recv_padding_buffer = new byte[256];
6348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	final byte[] recv_packet_header_buffer = new byte[5];
6548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	boolean recv_packet_header_present = false;
6748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
6848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	ClientServerHello csh;
6948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	final SecureRandom rnd;
7148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public TransportConnection(InputStream is, OutputStream os, SecureRandom rnd)
7348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
7448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		this.cis = new CipherInputStream(new NullCipher(), is);
7548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		this.cos = new CipherOutputStream(new NullCipher(), os);
7648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		this.rnd = rnd;
7748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
7848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
7948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public void changeRecvCipher(BlockCipher bc, MAC mac)
8048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
8148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cis.changeCipher(bc);
8248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		recv_mac = mac;
8348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		recv_mac_buffer = (mac != null) ? new byte[mac.size()] : null;
8448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		recv_mac_buffer_cmp = (mac != null) ? new byte[mac.size()] : null;
8548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		recv_padd_blocksize = bc.getBlockSize();
8648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (recv_padd_blocksize < 8)
8748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_padd_blocksize = 8;
8848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
8948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
9048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public void changeSendCipher(BlockCipher bc, MAC mac)
9148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
9248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if ((bc instanceof NullCipher) == false)
9348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
9448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			/* Only use zero byte padding for the first few packets */
9548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			useRandomPadding = true;
9648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			/* Once we start encrypting, there is no way back */
9748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
9848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
9948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cos.changeCipher(bc);
10048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_mac = mac;
10148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_mac_buffer = (mac != null) ? new byte[mac.size()] : null;
10248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_padd_blocksize = bc.getBlockSize();
10348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (send_padd_blocksize < 8)
10448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			send_padd_blocksize = 8;
10548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
10648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
10748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public void sendMessage(byte[] message) throws IOException
10848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
10948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		sendMessage(message, 0, message.length, 0);
11048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
11148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
11248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public void sendMessage(byte[] message, int off, int len) throws IOException
11348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
11448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		sendMessage(message, off, len, 0);
11548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
11648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
11748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int getPacketOverheadEstimate()
11848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
11948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		// return an estimate for the paket overhead (for send operations)
12048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return 5 + 4 + (send_padd_blocksize - 1) + send_mac_buffer.length;
12148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
12248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
12348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public void sendMessage(byte[] message, int off, int len, int padd) throws IOException
12448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
12548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (padd < 4)
12648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			padd = 4;
12748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		else if (padd > 64)
12848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			padd = 64;
12948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
13048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int packet_len = 5 + len + padd; /* Minimum allowed padding is 4 */
13148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
13248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int slack = packet_len % send_padd_blocksize;
13348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
13448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (slack != 0)
13548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
13648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			packet_len += (send_padd_blocksize - slack);
13748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
13848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
13948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (packet_len < 16)
14048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			packet_len = 16;
14148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
14248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int padd_len = packet_len - (5 + len);
14348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
14448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (useRandomPadding)
14548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
14648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			for (int i = 0; i < padd_len; i = i + 4)
14748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
14848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				/*
14948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				 * don't waste calls to rnd.nextInt() (by using only 8bit of the
15048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				 * output). just believe me: even though we may write here up to 3
15148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				 * bytes which won't be used, there is no "buffer overflow" (i.e.,
15248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				 * arrayindexoutofbounds). the padding buffer is big enough =) (256
15348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				 * bytes, and that is bigger than any current cipher block size + 64).
15448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				 */
15548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
15648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				int r = rnd.nextInt();
15748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				send_padding_buffer[i] = (byte) r;
15848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				send_padding_buffer[i + 1] = (byte) (r >> 8);
15948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				send_padding_buffer[i + 2] = (byte) (r >> 16);
16048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				send_padding_buffer[i + 3] = (byte) (r >> 24);
16148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
16248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
16348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		else
16448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
16548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			/* use zero padding for unencrypted traffic */
16648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			for (int i = 0; i < padd_len; i++)
16748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				send_padding_buffer[i] = 0;
16848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			/* Actually this code is paranoid: we never filled any
16948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			 * bytes into the padding buffer so far, therefore it should
17048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			 * consist of zeros only.
17148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			 */
17248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
17348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
17448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_packet_header_buffer[0] = (byte) ((packet_len - 4) >> 24);
17548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_packet_header_buffer[1] = (byte) ((packet_len - 4) >> 16);
17648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_packet_header_buffer[2] = (byte) ((packet_len - 4) >> 8);
17748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_packet_header_buffer[3] = (byte) ((packet_len - 4));
17848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_packet_header_buffer[4] = (byte) padd_len;
17948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
18048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cos.write(send_packet_header_buffer, 0, 5);
18148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cos.write(message, off, len);
18248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cos.write(send_padding_buffer, 0, padd_len);
18348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
18448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (send_mac != null)
18548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
18648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			send_mac.initMac(send_seq_number);
18748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			send_mac.update(send_packet_header_buffer, 0, 5);
18848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			send_mac.update(message, off, len);
18948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			send_mac.update(send_padding_buffer, 0, padd_len);
19048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
19148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			send_mac.getMac(send_mac_buffer, 0);
19248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			cos.writePlain(send_mac_buffer, 0, send_mac_buffer.length);
19348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
19448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
19548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cos.flush();
19648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
19748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (log.isDebugEnabled())
19848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
19948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			log.debug("Sent " + Packets.getMessageName(message[off] & 0xff) + " " + len + " bytes payload");
20048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
20148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
20248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		send_seq_number++;
20348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
20448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
20548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int peekNextMessageLength() throws IOException
20648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
20748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (recv_packet_header_present == false)
20848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
20948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			cis.read(recv_packet_header_buffer, 0, 5);
21048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_packet_header_present = true;
21148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
21248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
21348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24)
21448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				| ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8)
21548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				| ((recv_packet_header_buffer[3] & 0xff));
21648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
21748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int padding_length = recv_packet_header_buffer[4] & 0xff;
21848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
21948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (packet_length > 35000 || packet_length < 12)
22048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Illegal packet size! (" + packet_length + ")");
22148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
22248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int payload_length = packet_length - padding_length - 1;
22348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
22448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (payload_length < 0)
22548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Illegal padding_length in packet from remote (" + padding_length + ")");
22648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
22748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return payload_length;
22848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
22948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
23048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	public int receiveMessage(byte buffer[], int off, int len) throws IOException
23148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	{
23248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (recv_packet_header_present == false)
23348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
23448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			cis.read(recv_packet_header_buffer, 0, 5);
23548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
23648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		else
23748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_packet_header_present = false;
23848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
23948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24)
24048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				| ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8)
24148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				| ((recv_packet_header_buffer[3] & 0xff));
24248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
24348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int padding_length = recv_packet_header_buffer[4] & 0xff;
24448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
24548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (packet_length > 35000 || packet_length < 12)
24648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Illegal packet size! (" + packet_length + ")");
24748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
24848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		int payload_length = packet_length - padding_length - 1;
24948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
25048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (payload_length < 0)
25148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Illegal padding_length in packet from remote (" + padding_length + ")");
25248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
25348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (payload_length >= len)
25448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			throw new IOException("Receive buffer too small (" + len + ", need " + payload_length + ")");
25548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
25648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cis.read(buffer, off, payload_length);
25748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		cis.read(recv_padding_buffer, 0, padding_length);
25848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
25948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (recv_mac != null)
26048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
26148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			cis.readPlain(recv_mac_buffer, 0, recv_mac_buffer.length);
26248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
26348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_mac.initMac(recv_seq_number);
26448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_mac.update(recv_packet_header_buffer, 0, 5);
26548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_mac.update(buffer, off, payload_length);
26648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_mac.update(recv_padding_buffer, 0, padding_length);
26748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			recv_mac.getMac(recv_mac_buffer_cmp, 0);
26848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
26948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			for (int i = 0; i < recv_mac_buffer.length; i++)
27048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			{
27148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood				if (recv_mac_buffer[i] != recv_mac_buffer_cmp[i])
27248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood					throw new IOException("Remote sent corrupt MAC.");
27348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			}
27448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
27548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
27648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		recv_seq_number++;
27748ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
27848ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		if (log.isDebugEnabled())
27948ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		{
28048ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood			log.debug("Received " + Packets.getMessageName(buffer[off] & 0xff) + " " + payload_length
28148ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood					+ " bytes payload");
28248ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		}
28348ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood
28448ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood		return payload_length;
28548ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood	}
28648ded2421114c4c87ef3f8005c9f793a5d077cbdMike Lockwood}
287