Home | History | Annotate | Download | only in transport
      1 /*
      2  * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
      3  * Please refer to the LICENSE.txt for licensing details.
      4  */
      5 package ch.ethz.ssh2.transport;
      6 
      7 import java.io.IOException;
      8 import java.io.InputStream;
      9 import java.io.OutputStream;
     10 import java.security.SecureRandom;
     11 
     12 import ch.ethz.ssh2.crypto.cipher.BlockCipher;
     13 import ch.ethz.ssh2.crypto.cipher.CipherInputStream;
     14 import ch.ethz.ssh2.crypto.cipher.CipherOutputStream;
     15 import ch.ethz.ssh2.crypto.cipher.NullCipher;
     16 import ch.ethz.ssh2.crypto.digest.MAC;
     17 import ch.ethz.ssh2.log.Logger;
     18 import ch.ethz.ssh2.packets.Packets;
     19 
     20 /**
     21  * TransportConnection.
     22  *
     23  * @author Christian Plattner
     24  * @version $Id: TransportConnection.java 41 2011-06-02 10:36:41Z dkocher (at) sudo.ch $
     25  */
     26 public class TransportConnection
     27 {
     28 	private static final Logger log = Logger.getLogger(TransportConnection.class);
     29 
     30 	int send_seq_number = 0;
     31 
     32 	int recv_seq_number = 0;
     33 
     34 	CipherInputStream cis;
     35 
     36 	CipherOutputStream cos;
     37 
     38 	boolean useRandomPadding = false;
     39 
     40 	/* Depends on current MAC and CIPHER */
     41 
     42 	MAC send_mac;
     43 
     44 	byte[] send_mac_buffer;
     45 
     46 	int send_padd_blocksize = 8;
     47 
     48 	MAC recv_mac;
     49 
     50 	byte[] recv_mac_buffer;
     51 
     52 	byte[] recv_mac_buffer_cmp;
     53 
     54 	int recv_padd_blocksize = 8;
     55 
     56 	/* won't change */
     57 
     58 	final byte[] send_padding_buffer = new byte[256];
     59 
     60 	final byte[] send_packet_header_buffer = new byte[5];
     61 
     62 	final byte[] recv_padding_buffer = new byte[256];
     63 
     64 	final byte[] recv_packet_header_buffer = new byte[5];
     65 
     66 	boolean recv_packet_header_present = false;
     67 
     68 	ClientServerHello csh;
     69 
     70 	final SecureRandom rnd;
     71 
     72 	public TransportConnection(InputStream is, OutputStream os, SecureRandom rnd)
     73 	{
     74 		this.cis = new CipherInputStream(new NullCipher(), is);
     75 		this.cos = new CipherOutputStream(new NullCipher(), os);
     76 		this.rnd = rnd;
     77 	}
     78 
     79 	public void changeRecvCipher(BlockCipher bc, MAC mac)
     80 	{
     81 		cis.changeCipher(bc);
     82 		recv_mac = mac;
     83 		recv_mac_buffer = (mac != null) ? new byte[mac.size()] : null;
     84 		recv_mac_buffer_cmp = (mac != null) ? new byte[mac.size()] : null;
     85 		recv_padd_blocksize = bc.getBlockSize();
     86 		if (recv_padd_blocksize < 8)
     87 			recv_padd_blocksize = 8;
     88 	}
     89 
     90 	public void changeSendCipher(BlockCipher bc, MAC mac)
     91 	{
     92 		if ((bc instanceof NullCipher) == false)
     93 		{
     94 			/* Only use zero byte padding for the first few packets */
     95 			useRandomPadding = true;
     96 			/* Once we start encrypting, there is no way back */
     97 		}
     98 
     99 		cos.changeCipher(bc);
    100 		send_mac = mac;
    101 		send_mac_buffer = (mac != null) ? new byte[mac.size()] : null;
    102 		send_padd_blocksize = bc.getBlockSize();
    103 		if (send_padd_blocksize < 8)
    104 			send_padd_blocksize = 8;
    105 	}
    106 
    107 	public void sendMessage(byte[] message) throws IOException
    108 	{
    109 		sendMessage(message, 0, message.length, 0);
    110 	}
    111 
    112 	public void sendMessage(byte[] message, int off, int len) throws IOException
    113 	{
    114 		sendMessage(message, off, len, 0);
    115 	}
    116 
    117 	public int getPacketOverheadEstimate()
    118 	{
    119 		// return an estimate for the paket overhead (for send operations)
    120 		return 5 + 4 + (send_padd_blocksize - 1) + send_mac_buffer.length;
    121 	}
    122 
    123 	public void sendMessage(byte[] message, int off, int len, int padd) throws IOException
    124 	{
    125 		if (padd < 4)
    126 			padd = 4;
    127 		else if (padd > 64)
    128 			padd = 64;
    129 
    130 		int packet_len = 5 + len + padd; /* Minimum allowed padding is 4 */
    131 
    132 		int slack = packet_len % send_padd_blocksize;
    133 
    134 		if (slack != 0)
    135 		{
    136 			packet_len += (send_padd_blocksize - slack);
    137 		}
    138 
    139 		if (packet_len < 16)
    140 			packet_len = 16;
    141 
    142 		int padd_len = packet_len - (5 + len);
    143 
    144 		if (useRandomPadding)
    145 		{
    146 			for (int i = 0; i < padd_len; i = i + 4)
    147 			{
    148 				/*
    149 				 * don't waste calls to rnd.nextInt() (by using only 8bit of the
    150 				 * output). just believe me: even though we may write here up to 3
    151 				 * bytes which won't be used, there is no "buffer overflow" (i.e.,
    152 				 * arrayindexoutofbounds). the padding buffer is big enough =) (256
    153 				 * bytes, and that is bigger than any current cipher block size + 64).
    154 				 */
    155 
    156 				int r = rnd.nextInt();
    157 				send_padding_buffer[i] = (byte) r;
    158 				send_padding_buffer[i + 1] = (byte) (r >> 8);
    159 				send_padding_buffer[i + 2] = (byte) (r >> 16);
    160 				send_padding_buffer[i + 3] = (byte) (r >> 24);
    161 			}
    162 		}
    163 		else
    164 		{
    165 			/* use zero padding for unencrypted traffic */
    166 			for (int i = 0; i < padd_len; i++)
    167 				send_padding_buffer[i] = 0;
    168 			/* Actually this code is paranoid: we never filled any
    169 			 * bytes into the padding buffer so far, therefore it should
    170 			 * consist of zeros only.
    171 			 */
    172 		}
    173 
    174 		send_packet_header_buffer[0] = (byte) ((packet_len - 4) >> 24);
    175 		send_packet_header_buffer[1] = (byte) ((packet_len - 4) >> 16);
    176 		send_packet_header_buffer[2] = (byte) ((packet_len - 4) >> 8);
    177 		send_packet_header_buffer[3] = (byte) ((packet_len - 4));
    178 		send_packet_header_buffer[4] = (byte) padd_len;
    179 
    180 		cos.write(send_packet_header_buffer, 0, 5);
    181 		cos.write(message, off, len);
    182 		cos.write(send_padding_buffer, 0, padd_len);
    183 
    184 		if (send_mac != null)
    185 		{
    186 			send_mac.initMac(send_seq_number);
    187 			send_mac.update(send_packet_header_buffer, 0, 5);
    188 			send_mac.update(message, off, len);
    189 			send_mac.update(send_padding_buffer, 0, padd_len);
    190 
    191 			send_mac.getMac(send_mac_buffer, 0);
    192 			cos.writePlain(send_mac_buffer, 0, send_mac_buffer.length);
    193 		}
    194 
    195 		cos.flush();
    196 
    197 		if (log.isDebugEnabled())
    198 		{
    199 			log.debug("Sent " + Packets.getMessageName(message[off] & 0xff) + " " + len + " bytes payload");
    200 		}
    201 
    202 		send_seq_number++;
    203 	}
    204 
    205 	public int peekNextMessageLength() throws IOException
    206 	{
    207 		if (recv_packet_header_present == false)
    208 		{
    209 			cis.read(recv_packet_header_buffer, 0, 5);
    210 			recv_packet_header_present = true;
    211 		}
    212 
    213 		int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24)
    214 				| ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8)
    215 				| ((recv_packet_header_buffer[3] & 0xff));
    216 
    217 		int padding_length = recv_packet_header_buffer[4] & 0xff;
    218 
    219 		if (packet_length > 35000 || packet_length < 12)
    220 			throw new IOException("Illegal packet size! (" + packet_length + ")");
    221 
    222 		int payload_length = packet_length - padding_length - 1;
    223 
    224 		if (payload_length < 0)
    225 			throw new IOException("Illegal padding_length in packet from remote (" + padding_length + ")");
    226 
    227 		return payload_length;
    228 	}
    229 
    230 	public int receiveMessage(byte buffer[], int off, int len) throws IOException
    231 	{
    232 		if (recv_packet_header_present == false)
    233 		{
    234 			cis.read(recv_packet_header_buffer, 0, 5);
    235 		}
    236 		else
    237 			recv_packet_header_present = false;
    238 
    239 		int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24)
    240 				| ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8)
    241 				| ((recv_packet_header_buffer[3] & 0xff));
    242 
    243 		int padding_length = recv_packet_header_buffer[4] & 0xff;
    244 
    245 		if (packet_length > 35000 || packet_length < 12)
    246 			throw new IOException("Illegal packet size! (" + packet_length + ")");
    247 
    248 		int payload_length = packet_length - padding_length - 1;
    249 
    250 		if (payload_length < 0)
    251 			throw new IOException("Illegal padding_length in packet from remote (" + padding_length + ")");
    252 
    253 		if (payload_length >= len)
    254 			throw new IOException("Receive buffer too small (" + len + ", need " + payload_length + ")");
    255 
    256 		cis.read(buffer, off, payload_length);
    257 		cis.read(recv_padding_buffer, 0, padding_length);
    258 
    259 		if (recv_mac != null)
    260 		{
    261 			cis.readPlain(recv_mac_buffer, 0, recv_mac_buffer.length);
    262 
    263 			recv_mac.initMac(recv_seq_number);
    264 			recv_mac.update(recv_packet_header_buffer, 0, 5);
    265 			recv_mac.update(buffer, off, payload_length);
    266 			recv_mac.update(recv_padding_buffer, 0, padding_length);
    267 			recv_mac.getMac(recv_mac_buffer_cmp, 0);
    268 
    269 			for (int i = 0; i < recv_mac_buffer.length; i++)
    270 			{
    271 				if (recv_mac_buffer[i] != recv_mac_buffer_cmp[i])
    272 					throw new IOException("Remote sent corrupt MAC.");
    273 			}
    274 		}
    275 
    276 		recv_seq_number++;
    277 
    278 		if (log.isDebugEnabled())
    279 		{
    280 			log.debug("Received " + Packets.getMessageName(buffer[off] & 0xff) + " " + payload_length
    281 					+ " bytes payload");
    282 		}
    283 
    284 		return payload_length;
    285 	}
    286 }
    287