1 2 package ch.ethz.ssh2.transport; 3 4 import java.io.IOException ; 5 import java.io.InputStream ; 6 import java.io.OutputStream ; 7 import java.security.SecureRandom ; 8 9 import ch.ethz.ssh2.crypto.cipher.BlockCipher; 10 import ch.ethz.ssh2.crypto.cipher.CipherInputStream; 11 import ch.ethz.ssh2.crypto.cipher.CipherOutputStream; 12 import ch.ethz.ssh2.crypto.cipher.NullCipher; 13 import ch.ethz.ssh2.crypto.digest.MAC; 14 import ch.ethz.ssh2.log.Logger; 15 import ch.ethz.ssh2.packets.Packets; 16 17 23 public class TransportConnection 24 { 25 private static final Logger log = Logger.getLogger(TransportConnection.class); 26 27 int send_seq_number = 0; 28 29 int recv_seq_number = 0; 30 31 CipherInputStream cis; 32 33 CipherOutputStream cos; 34 35 boolean useRandomPadding = false; 36 37 38 39 MAC send_mac; 40 41 byte[] send_mac_buffer; 42 43 int send_padd_blocksize = 8; 44 45 MAC recv_mac; 46 47 byte[] recv_mac_buffer; 48 49 byte[] recv_mac_buffer_cmp; 50 51 int recv_padd_blocksize = 8; 52 53 54 55 final byte[] send_padding_buffer = new byte[256]; 56 57 final byte[] send_packet_header_buffer = new byte[5]; 58 59 final byte[] recv_padding_buffer = new byte[256]; 60 61 final byte[] recv_packet_header_buffer = new byte[5]; 62 63 boolean recv_packet_header_present = false; 64 65 ClientServerHello csh; 66 67 final SecureRandom rnd; 68 69 public TransportConnection(InputStream is, OutputStream os, SecureRandom rnd) 70 { 71 this.cis = new CipherInputStream(new NullCipher(), is); 72 this.cos = new CipherOutputStream(new NullCipher(), os); 73 this.rnd = rnd; 74 } 75 76 public void changeRecvCipher(BlockCipher bc, MAC mac) 77 { 78 cis.changeCipher(bc); 79 recv_mac = mac; 80 recv_mac_buffer = (mac != null) ? new byte[mac.size()] : null; 81 recv_mac_buffer_cmp = (mac != null) ? new byte[mac.size()] : null; 82 recv_padd_blocksize = bc.getBlockSize(); 83 if (recv_padd_blocksize < 8) 84 recv_padd_blocksize = 8; 85 } 86 87 public void changeSendCipher(BlockCipher bc, MAC mac) 88 { 89 if ((bc instanceof NullCipher) == false) 90 { 91 92 useRandomPadding = true; 93 94 } 95 96 cos.changeCipher(bc); 97 send_mac = mac; 98 send_mac_buffer = (mac != null) ? new byte[mac.size()] : null; 99 send_padd_blocksize = bc.getBlockSize(); 100 if (send_padd_blocksize < 8) 101 send_padd_blocksize = 8; 102 } 103 104 public void sendMessage(byte[] message) throws IOException 105 { 106 sendMessage(message, 0, message.length, 0); 107 } 108 109 public void sendMessage(byte[] message, int off, int len) throws IOException 110 { 111 sendMessage(message, off, len, 0); 112 } 113 114 public int getPacketOverheadEstimate() 115 { 116 return 5 + 4 + (send_padd_blocksize - 1) + send_mac_buffer.length; 118 } 119 120 public void sendMessage(byte[] message, int off, int len, int padd) throws IOException 121 { 122 if (padd < 4) 123 padd = 4; 124 else if (padd > 64) 125 padd = 64; 126 127 int packet_len = 5 + len + padd; 128 129 int slack = packet_len % send_padd_blocksize; 130 131 if (slack != 0) 132 { 133 packet_len += (send_padd_blocksize - slack); 134 } 135 136 if (packet_len < 16) 137 packet_len = 16; 138 139 int padd_len = packet_len - (5 + len); 140 141 if (useRandomPadding) 142 { 143 for (int i = 0; i < padd_len; i = i + 4) 144 { 145 152 153 int r = rnd.nextInt(); 154 send_padding_buffer[i] = (byte) r; 155 send_padding_buffer[i + 1] = (byte) (r >> 8); 156 send_padding_buffer[i + 2] = (byte) (r >> 16); 157 send_padding_buffer[i + 3] = (byte) (r >> 24); 158 } 159 } 160 else 161 { 162 163 for (int i = 0; i < padd_len; i++) 164 send_padding_buffer[i] = 0; 165 169 } 170 171 send_packet_header_buffer[0] = (byte) ((packet_len - 4) >> 24); 172 send_packet_header_buffer[1] = (byte) ((packet_len - 4) >> 16); 173 send_packet_header_buffer[2] = (byte) ((packet_len - 4) >> 8); 174 send_packet_header_buffer[3] = (byte) ((packet_len - 4)); 175 send_packet_header_buffer[4] = (byte) padd_len; 176 177 cos.write(send_packet_header_buffer, 0, 5); 178 cos.write(message, off, len); 179 cos.write(send_padding_buffer, 0, padd_len); 180 181 if (send_mac != null) 182 { 183 send_mac.initMac(send_seq_number); 184 send_mac.update(send_packet_header_buffer, 0, 5); 185 send_mac.update(message, off, len); 186 send_mac.update(send_padding_buffer, 0, padd_len); 187 188 send_mac.getMac(send_mac_buffer, 0); 189 cos.writePlain(send_mac_buffer, 0, send_mac_buffer.length); 190 } 191 192 cos.flush(); 193 194 if (log.isEnabled()) 195 { 196 log.log(90, "Sent " + Packets.getMessageName(message[off] & 0xff) + " " + len + " bytes payload"); 197 } 198 199 send_seq_number++; 200 } 201 202 public int peekNextMessageLength() throws IOException 203 { 204 if (recv_packet_header_present == false) 205 { 206 cis.read(recv_packet_header_buffer, 0, 5); 207 recv_packet_header_present = true; 208 } 209 210 int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24) 211 | ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8) 212 | ((recv_packet_header_buffer[3] & 0xff)); 213 214 int padding_length = recv_packet_header_buffer[4] & 0xff; 215 216 if (packet_length > 35000 || packet_length < 12) 217 throw new IOException ("Illegal packet size! (" + packet_length + ")"); 218 219 int payload_length = packet_length - padding_length - 1; 220 221 if (payload_length < 0) 222 throw new IOException ("Illegal padding_length in packet from remote (" + padding_length + ")"); 223 224 return payload_length; 225 } 226 227 public int receiveMessage(byte buffer[], int off, int len) throws IOException 228 { 229 if (recv_packet_header_present == false) 230 { 231 cis.read(recv_packet_header_buffer, 0, 5); 232 } 233 else 234 recv_packet_header_present = false; 235 236 int packet_length = ((recv_packet_header_buffer[0] & 0xff) << 24) 237 | ((recv_packet_header_buffer[1] & 0xff) << 16) | ((recv_packet_header_buffer[2] & 0xff) << 8) 238 | ((recv_packet_header_buffer[3] & 0xff)); 239 240 int padding_length = recv_packet_header_buffer[4] & 0xff; 241 242 if (packet_length > 35000 || packet_length < 12) 243 throw new IOException ("Illegal packet size! (" + packet_length + ")"); 244 245 int payload_length = packet_length - padding_length - 1; 246 247 if (payload_length < 0) 248 throw new IOException ("Illegal padding_length in packet from remote (" + padding_length + ")"); 249 250 if (payload_length >= len) 251 throw new IOException ("Receive buffer too small (" + len + ", need " + payload_length + ")"); 252 253 cis.read(buffer, off, payload_length); 254 cis.read(recv_padding_buffer, 0, padding_length); 255 256 if (recv_mac != null) 257 { 258 cis.readPlain(recv_mac_buffer, 0, recv_mac_buffer.length); 259 260 recv_mac.initMac(recv_seq_number); 261 recv_mac.update(recv_packet_header_buffer, 0, 5); 262 recv_mac.update(buffer, off, payload_length); 263 recv_mac.update(recv_padding_buffer, 0, padding_length); 264 recv_mac.getMac(recv_mac_buffer_cmp, 0); 265 266 for (int i = 0; i < recv_mac_buffer.length; i++) 267 { 268 if (recv_mac_buffer[i] != recv_mac_buffer_cmp[i]) 269 throw new IOException ("Remote sent corrupt MAC."); 270 } 271 } 272 273 recv_seq_number++; 274 275 if (log.isEnabled()) 276 { 277 log.log(90, "Received " + Packets.getMessageName(buffer[off] & 0xff) + " " + payload_length 278 + " bytes payload"); 279 } 280 281 return payload_length; 282 } 283 } 284 | Popular Tags |