public void OnPacket(SSH2Packet packet) { lock (this) { _packets.Add(packet); if (_packets.Count > 0) { SetReady(); } } }
//returns true if a new packet could be obtained private SSH2Packet ConstructPacket() { SSH2Packet packet = null; if (_event != null && !_event.WaitOne(3000, false)) { throw new Exception("waithandle timed out"); } if (_cipher == null) { if (_writeOffset - _readOffset < 4) { return(null); } int len = SSHUtil.ReadInt32(_buffer, _readOffset); if (_writeOffset - _readOffset < 4 + len) { return(null); } packet = SSH2Packet.FromPlainStream(_buffer, _readOffset); _readOffset += 4 + len; _sequence++; } else { if (_head == null) { if (_writeOffset - _readOffset < _cipher.BlockSize) { return(null); } _head = new byte[_cipher.BlockSize]; byte[] eh = new byte[_cipher.BlockSize]; Array.Copy(_buffer, _readOffset, eh, 0, eh.Length); _readOffset += eh.Length; _cipher.Decrypt(eh, 0, eh.Length, _head, 0); } int len = SSHUtil.ReadInt32(_head, 0); if (_writeOffset - _readOffset < len + 4 - _head.Length + _mac.Size) { return(null); } packet = SSH2Packet.FromDecryptedHead(_head, _buffer, _readOffset, _cipher, _sequence++, _mac); _readOffset += 4 + len - _head.Length + _mac.Size; _head = null; } return(packet); }
public static SSH2Packet FromPlainPayload(byte[] payload, int blocksize, Random rnd) { SSH2Packet p = new SSH2Packet(); int r = 11 - payload.Length % blocksize; while (r < 4) { r += blocksize; } p._padding = new byte[r]; //block size is 8, and padding length is at least 4 bytes rnd.NextBytes(p._padding); p._payload = payload; p._packetLength = 1 + payload.Length + p._padding.Length; return(p); }
public static SSH2Packet FromDecryptedHead(byte[] head, byte[] buffer, int offset, Cipher cipher, int sequence, MAC mac) { SSH2Packet p = new SSH2Packet(); p._packetLength = SSHUtil.ReadInt32(head, 0); if (p._packetLength <= 0 || p._packetLength >= MAX_PACKET_LENGTH) { throw new SSHException(String.Format("packet size {0} is invalid", p._packetLength)); } SSH2DataWriter buf = new SSH2DataWriter(); buf.Write(sequence); buf.Write(head); if (p._packetLength > (cipher.BlockSize - 4)) { byte[] tmp = new byte[p._packetLength - (cipher.BlockSize - 4)]; cipher.Decrypt(buffer, offset, tmp.Length, tmp, 0); offset += tmp.Length; buf.Write(tmp); } byte[] result = buf.ToByteArray(); int padding_len = (int)result[8]; if (padding_len < 4) { throw new SSHException("padding length is invalid"); } byte[] payload = new byte[result.Length - 9 - padding_len]; Array.Copy(result, 9, payload, 0, payload.Length); p._payload = payload; if (mac != null) { p._mac = mac.Calc(result); if (SSHUtil.memcmp(p._mac, 0, buffer, offset, mac.Size) != 0) { throw new SSHException("MAC Error"); } } return(p); }
public SSH2Packet PopPacket() { lock (this) { if (_packets.Count == 0) { return(null); } else { SSH2Packet p = null; p = (SSH2Packet)_packets[0]; _packets.RemoveAt(0); if (_packets.Count == 0) { _event.Reset(); } return(p); } } }
//no decryption, no mac public static SSH2Packet FromPlainStream(byte[] buffer, int offset) { SSH2Packet p = new SSH2Packet(); p._packetLength = SSHUtil.ReadInt32(buffer, offset); if (p._packetLength <= 0 || p._packetLength >= MAX_PACKET_LENGTH) { throw new SSHException(String.Format("packet size {0} is invalid", p._packetLength)); } offset += 4; byte pl = buffer[offset++]; if (pl < 4) { throw new SSHException(String.Format("padding length {0} is invalid", pl)); } p._payload = new byte[p._packetLength - 1 - pl]; Array.Copy(buffer, offset, p._payload, 0, p._payload.Length); return(p); }
public void OnData(byte[] data, int offset, int length) { try { while (_buffer.Length - _writeOffset < length) { ExpandBuffer(); } Array.Copy(data, offset, _buffer, _writeOffset, length); _writeOffset += length; SSH2Packet p = ConstructPacket(); while (p != null) { _handler.OnPacket(p); p = ConstructPacket(); } ReduceBuffer(); } catch (Exception ex) { OnError(ex, ex.Message); } }
private void ProcessKEXINIT(SSH2Packet packet) { _serverKEXINITPayload = packet.Data; SSH2DataReader re = new SSH2DataReader(_serverKEXINITPayload); byte[] head = re.Read(17); //Type and cookie if(head[0]!=(byte)PacketType.SSH_MSG_KEXINIT) throw new SSHException(String.Format("Server response is not SSH_MSG_KEXINIT but {0}", head[0])); Encoding enc = Encoding.ASCII; string kex = enc.GetString(re.ReadString()); _cInfo._supportedKEXAlgorithms = kex; CheckAlgorithmSupport("keyexchange", kex, "diffie-hellman-group1-sha1"); string host_key = enc.GetString(re.ReadString()); _cInfo._supportedHostKeyAlgorithms = host_key; _cInfo._algorithmForHostKeyVerification = DecideHostKeyAlgorithm(host_key); string enc_cs = enc.GetString(re.ReadString()); _cInfo._supportedCipherAlgorithms = enc_cs; _cInfo._algorithmForTransmittion = DecideCipherAlgorithm(enc_cs); string enc_sc = enc.GetString(re.ReadString()); _cInfo._algorithmForReception = DecideCipherAlgorithm(enc_sc); string mac_cs = enc.GetString(re.ReadString()); CheckAlgorithmSupport("mac", mac_cs, "hmac-sha1"); string mac_sc = enc.GetString(re.ReadString()); CheckAlgorithmSupport("mac", mac_sc, "hmac-sha1"); string comp_cs = enc.GetString(re.ReadString()); CheckAlgorithmSupport("compression", comp_cs, "none"); string comp_sc = enc.GetString(re.ReadString()); CheckAlgorithmSupport("compression", comp_sc, "none"); string lang_cs = enc.GetString(re.ReadString()); string lang_sc = enc.GetString(re.ReadString()); bool flag = re.ReadBool(); int reserved = re.ReadInt32(); Debug.Assert(re.Rest==0); if(flag) throw new SSHException("Algorithm negotiation failed"); }
private bool ProcessKEXDHREPLY(SSH2Packet packet) { //Round2 receives response SSH2DataReader re = new SSH2DataReader(packet.Data); PacketType h = re.ReadPacketType(); if(h!=PacketType.SSH_MSG_KEXDH_REPLY) throw new SSHException(String.Format("KeyExchange response is not KEXDH_REPLY but {0}", h)); byte[] key_and_cert = re.ReadString(); BigInteger f = re.ReadMPInt(); byte[] signature = re.ReadString(); Debug.Assert(re.Rest==0); //Round3 calc hash H SSH2DataWriter wr = new SSH2DataWriter(); _k = f.modPow(_x, DH_PRIME); wr = new SSH2DataWriter(); wr.Write(_cInfo._clientVersionString); wr.Write(_cInfo._serverVersionString); wr.WriteAsString(_clientKEXINITPayload); wr.WriteAsString(_serverKEXINITPayload); wr.WriteAsString(key_and_cert); wr.Write(_e); wr.Write(f); wr.Write(_k); _hash = new SHA1CryptoServiceProvider().ComputeHash(wr.ToByteArray()); if(!VerifyHostKey(key_and_cert, signature, _hash)) return false; //Debug.WriteLine("hash="+DebugUtil.DumpByteArray(hash)); if(_sessionID==null) _sessionID = _hash; return true; }
public void OnPacket(SSH2Packet packet) { _connection.AsyncReceivePacket(packet); }
public void OnPacket(SSH2Packet packet) { lock(this) { _packets.Add(packet); if(_packets.Count > 0) SetReady(); } }
//no decryption, no mac public static SSH2Packet FromPlainStream(byte[] buffer, int offset) { SSH2Packet p = new SSH2Packet(); p._packetLength = SSHUtil.ReadInt32(buffer, offset); if(p._packetLength<=0 || p._packetLength>=MAX_PACKET_LENGTH) throw new SSHException(String.Format("packet size {0} is invalid", p._packetLength)); offset += 4; byte pl = buffer[offset++]; if(pl < 4) throw new SSHException(String.Format("padding length {0} is invalid", pl)); p._payload = new byte[p._packetLength - 1 - pl]; Array.Copy(buffer, offset, p._payload, 0, p._payload.Length); return p; }
private bool ProcessPacket(SSH2Packet packet) { SSH2DataReader r = new SSH2DataReader(packet.Data); PacketType pt = r.ReadPacketType(); //Debug.WriteLine("ProcessPacket pt="+pt); if(pt==PacketType.SSH_MSG_DISCONNECT) { int errorcode = r.ReadInt32(); //string description = Encoding.ASCII.GetString(r.ReadString()); _eventReceiver.OnConnectionClosed(); return false; } else if(_waitingForPortForwardingResponse) { if(pt!=PacketType.SSH_MSG_REQUEST_SUCCESS) _eventReceiver.OnUnknownMessage((byte)pt, r.Image); _waitingForPortForwardingResponse = false; return true; } else if(pt==PacketType.SSH_MSG_CHANNEL_OPEN) { ProcessPortforwardingRequest(_eventReceiver, r); return true; } else if(pt>=PacketType.SSH_MSG_CHANNEL_OPEN_CONFIRMATION && pt<=PacketType.SSH_MSG_CHANNEL_FAILURE) { int local_channel = r.ReadInt32(); ChannelEntry e = FindChannelEntry(local_channel); if(e!=null) //throw new SSHException("Unknown channel "+local_channel); ((SSH2Channel)e._channel).ProcessPacket(e._receiver, pt, 5+r.Rest, r); else Debug.WriteLine("unexpected channel pt="+pt+" local_channel="+local_channel.ToString()); return true; } else if(pt==PacketType.SSH_MSG_IGNORE) { _eventReceiver.OnIgnoreMessage(r.ReadString()); return true; } else if(_asyncKeyExchanger!=null) { _asyncKeyExchanger.AsyncProcessPacket(packet); return true; } else if(pt==PacketType.SSH_MSG_KEXINIT) { //Debug.WriteLine("Host sent KEXINIT"); _asyncKeyExchanger = new KeyExchanger(this, _sessionID); _asyncKeyExchanger.AsyncProcessPacket(packet); return true; } else { _eventReceiver.OnUnknownMessage((byte)pt, r.Image); return false; } }
private void ProcessNEWKEYS(SSH2Packet packet) { //confirms new key try { byte[] response = packet.Data; if(response.Length!=1 || response[0]!=(byte)PacketType.SSH_MSG_NEWKEYS) throw new SSHException("SSH_MSG_NEWKEYS failed"); _newKeyEvent.WaitOne(); _newKeyEvent.Close(); _con.LockCommunication(); _con.RefreshKeys(_sessionID, _tc, _rc, _tm, _rm); _status = Status.FINISHED; } finally { _con.UnlockCommunication(); } }
internal void AsyncReceivePacket(SSH2Packet packet) { try { ProcessPacket(packet); } catch(Exception ex) { //Debug.WriteLine(ex.StackTrace); if(!_closed) _eventReceiver.OnError(ex, ex.Message); } }
public static SSH2Packet FromDecryptedHead(byte[] head, byte[] buffer, int offset, Cipher cipher, int sequence, MAC mac) { SSH2Packet p = new SSH2Packet(); p._packetLength = SSHUtil.ReadInt32(head, 0); if(p._packetLength<=0 || p._packetLength>=MAX_PACKET_LENGTH) throw new SSHException(String.Format("packet size {0} is invalid", p._packetLength)); SSH2DataWriter buf = new SSH2DataWriter(); buf.Write(sequence); buf.Write(head); if(p._packetLength > (cipher.BlockSize - 4)) { byte[] tmp = new byte[p._packetLength-(cipher.BlockSize - 4)]; cipher.Decrypt(buffer, offset, tmp.Length, tmp, 0); offset += tmp.Length; buf.Write(tmp); } byte[] result = buf.ToByteArray(); int padding_len = (int)result[8]; if(padding_len<4) throw new SSHException("padding length is invalid"); byte[] payload = new byte[result.Length-9-padding_len]; Array.Copy(result, 9, payload, 0, payload.Length); p._payload = payload; if(mac!=null) { p._mac = mac.Calc(result); if(SSHUtil.memcmp(p._mac, 0, buffer, offset, mac.Size)!=0) throw new SSHException("MAC Error"); } return p; }
public void AsyncProcessPacket(SSH2Packet packet) { switch(_status) { case Status.INITIAL: _startedByHost = true; ProcessKEXINIT(packet); SendKEXINIT(); SendKEXDHINIT(); break; case Status.WAIT_KEXINIT: ProcessKEXINIT(packet); SendKEXDHINIT(); break; case Status.WAIT_KEXDH_REPLY: ProcessKEXDHREPLY(packet); SendNEWKEYS(); break; case Status.WAIT_NEWKEYS: ProcessNEWKEYS(packet); Debug.Assert(_status==Status.FINISHED); break; } }
public static SSH2Packet FromPlainPayload(byte[] payload, int blocksize, Random rnd) { SSH2Packet p = new SSH2Packet(); int r = 11 - payload.Length % blocksize; while(r < 4) r += blocksize; p._padding = new byte[r]; //block size is 8, and padding length is at least 4 bytes rnd.NextBytes(p._padding); p._payload = payload; p._packetLength = 1+payload.Length+p._padding.Length; return p; }