/// <summary> /// Send a message to the remote side of the connection. /// </summary> /// <param name="packet"></param> /// <param name="returnPayload">Return the unecrypted payload of this packet.</param> public byte[] SendMessage(SSHPacket packet, bool returnPayload) { byte[] payload = null; lock (this) { if (currentState == TransportProtocolState.PERFORMING_KEYEXCHANGE && !IsTransportMessage(packet.MessageID)) { lock (kexqueue) { kexqueue.Add(packet); return(payload); } } try { int padding = 4; // Compress the payload if necersary /*if (outgoingCompression != null) * { * msgdata = outgoingCompression.compress(msgdata, 0, msgdata.Length); * }*/ // Determine the padding length padding += ((outgoingCipherLength - ((packet.Length + padding) % outgoingCipherLength)) % outgoingCipherLength); packet.MoveToPosition(0); // Write the packet length field packet.WriteUINT32(packet.Length - 4 + padding); // Write the padding length packet.WriteByte((byte)padding); // Now skip back up to the end of the packet packet.MoveToEnd(); if (returnPayload) { payload = packet.Payload; } // Create some random data for the padding byte[] pad = new byte[padding]; rnd.GetBytes(pad); packet.WriteBytes(pad); // Generate the MAC if (outgoingMac != null) { outgoingMac.Generate(outgoingSequence, packet.Array, 0, packet.Length, packet.Array, packet.Length); } // Perfrom encrpytion if (encryption != null) { encryption.Transform(packet.Array, 0, packet.Array, 0, packet.Length); } packet.Skip(outgoingMacLength); outgoingBytes += packet.Length; // Send! packet.WriteToStream(transport.GetStream()); outgoingSequence++; numOutgoingBytesSinceKEX += (uint)packet.Length; numOutgoingSSHPacketsSinceKEX++; ReleaseSSHPacket(packet); if (outgoingSequence > 4294967295) { outgoingSequence = 0; } if (numOutgoingBytesSinceKEX >= MAX_NUM_BYTES_BEFORE_REKEY || numOutgoingSSHPacketsSinceKEX >= MAX_NUM_PACKETS_BEFORE_REKEY) { SendKeyExchangeInit(); } } catch (System.IO.IOException ex) { InternalDisconnect(); throw new SSHException("Unexpected termination: " + ex.Message, SSHException.UNEXPECTED_TERMINATION); } catch (System.ObjectDisposedException ex) { InternalDisconnect(); throw new SSHException("Unexpected terminaton: " + ex.Message, SSHException.UNEXPECTED_TERMINATION); } } return(payload); }
internal SSHPacket ReadMessage() { lock (kexlock) { try { SSHPacket packet = GetSSHPacket(false); packet.ReadFromStream(transport.GetStream(), incomingCipherLength); // Mark the current position so we can read more data packet.Mark(); packet.MoveToPosition(0); // Decrypt the data if we have a valid cipher if (decryption != null) { decryption.Transform(packet.Array, 0, packet.Array, 0, incomingCipherLength); } int msglen = (int)packet.ReadUINT32(); int padlen = packet.ReadByte(); int remaining = (msglen - (incomingCipherLength - 4)); // Verify that the packet length is good if (remaining < 0) { InternalDisconnect(); throw new SSHException("EOF whilst reading message data block", SSHException.UNEXPECTED_TERMINATION); } else if (remaining > packet.Limit - packet.Length) { InternalDisconnect(); throw new SSHException("Incoming packet length violates SSH protocol", SSHException.UNEXPECTED_TERMINATION); } // Read, decrypt and save the remaining data packet.MoveToMark(); packet.ReadFromStream(transport.GetStream(), remaining); if (decryption != null) { decryption.Transform(packet.Array, incomingCipherLength, packet.Array, incomingCipherLength, remaining); } // Tell the packet where the payload ends //packet.PayloadLength = (int)msglen - padlen - 1; if (incomingMac != null) { packet.ReadFromStream(transport.GetStream(), incomingMacLength); // Verify the mac if (!incomingMac.Verify(incomingSequence, packet.Array, 0, incomingCipherLength + remaining, packet.Array, incomingCipherLength + remaining)) { Disconnect("Corrupt Mac on input", DisconnectionReason.MAC_ERROR); throw new SSHException("Corrupt Mac on input", SSHException.PROTOCOL_VIOLATION); } } if (++incomingSequence > 4294967295) { incomingSequence = 0; } incomingBytes += incomingCipherLength + remaining + incomingMacLength; // Uncompress the message payload if necersary /*if (incomingCompression != null) * { * return incomingCompression.uncompress(payload, 0, payload.Length); * }*/ numIncomingBytesSinceKEX += (uint)packet.Length; numIncomingSSHPacketsSinceKEX++; if (numIncomingBytesSinceKEX >= MAX_NUM_BYTES_BEFORE_REKEY || numIncomingSSHPacketsSinceKEX >= MAX_NUM_PACKETS_BEFORE_REKEY) { SendKeyExchangeInit(); } // Get the packet ready for reading packet.MoveToPosition(6); return(packet); } catch (System.ObjectDisposedException ex) { InternalDisconnect(); throw new SSHException("Unexpected terminaton: " + ex.Message, SSHException.UNEXPECTED_TERMINATION); } catch (System.IO.IOException ex) { InternalDisconnect(); throw new SSHException("Unexpected terminaton: " + (ex.Message != null? ex.Message:ex.GetType().FullName) + " sequenceNo = " + incomingSequence + " bytesIn = " + incomingBytes + " bytesOut = " + outgoingBytes, SSHException.UNEXPECTED_TERMINATION); } } }