private void InternalWritePacket(IPacket p) { if (!socket.Connected) { return; } byte paddingLength; var payload = p.ToSshMessage(); switch (SocketModeTx) { case Mode.Ascii: { var data = payload.Concat(new byte[] { (byte)'\r', (byte)'\n' }).ToArray(); st.Write(data, 0, data.Length); SocketModeTx = Mode.PlainText; break; } case Mode.PlainText: { ClientSequence++; int packetLength = GetPacketLength(payload.Length, out paddingLength); pw.WriteInt32(packetLength); pw.Write(paddingLength); pw.Write(payload); pw.Write(new byte[paddingLength]); break; } case Mode.CipherText: { if (txCompressionEnabled || (txCompressionEnabled = IsTxCompressionEnabled())) { if (TxZlibTransform == null) { TxZlibTransform = new ZlibTransform(CompressionMode.Compress); } var compressedLength = TxZlibTransform.TransformBlock(payload, 0, payload.Length, zlibTxBuffer, 0); Debug.WriteLine(string.Format("Compression Out: In: {0}; Out: {1}; TotalIn: {2}; TotalOut: {3}; TotalRatio: {4}", payload.Length, compressedLength, TxZlibTransform.TotalIn, TxZlibTransform.TotalOut, TxZlibTransform.Ratio)); payload = new byte[compressedLength]; Buffer.BlockCopy(zlibTxBuffer, 0, payload, 0, compressedLength); } var hmac = EncryptorMac; int packetLength = GetPacketLength(payload.Length, out paddingLength); byte[] padding = new byte[paddingLength]; Extensions.Random.GetBytes(padding); hmac.WriteUInt32(ClientSequence++); hmac.WriteInt32(packetLength); hmac.Write(paddingLength); hmac.Write(payload); hmac.Write(padding); pw.WriteInt32(packetLength); pw.Write(paddingLength); pw.Write(payload); pw.Write(padding); // mac isn't encrypted, write directly to network stream st.Write(hmac.Hash, 0, hmac.BlockSize); hmac.Reset(); break; } } if (p.Code == MessageCode.SSH_MSG_NEWKEYS) { SocketModeTx = Mode.CipherText; pw = new PacketWriter(new CryptoStream(st, Encryptor, CryptoStreamMode.Write)); } }
private IPacket PrivateReadPacket() { IPacket p = null; switch (SocketModeRx) { case Mode.Ascii: { p = new SshIdentification(pr.ReadLine().ToByteArray()); break; } case Mode.PlainText: { ServerSequence++; int packetLength = pr.ReadInt32(); byte paddingLength = pr.ReadByte(); var payload = pr.ReadBytes(packetLength - paddingLength - 1); pr.ReadBytes(paddingLength); p = PacketFactory.Create(session, payload); break; } case Mode.CipherText: { if (Decryptor == null) { session.KexProcessor.Wait(); } int packetLength = pr.ReadInt32(); byte paddingLength = pr.ReadByte(); var payload = pr.ReadBytes(packetLength - paddingLength - 1); var padding = pr.ReadBytes(paddingLength); var hmac = DecryptorMac; hmac.WriteUInt32(ServerSequence++); hmac.WriteInt32(packetLength); hmac.Write(paddingLength); hmac.Write(payload); hmac.Write(padding); if (rxCompressionEnabled || (rxCompressionEnabled = IsRxCompressionEnabled())) { if (RxZlibTransform == null) { RxZlibTransform = new ZlibTransform(CompressionMode.Decompress); } var length = RxZlibTransform.TransformBlock(payload, 0, payload.Length, zlibRxBuffer, 0); Debug.WriteLine(string.Format("Compression In: In: {0}; Out: {1}; TotalIn: {2}; TotalOut: {3}; TotalRatio: {4}", payload.Length, length, RxZlibTransform.TotalIn, RxZlibTransform.TotalOut, RxZlibTransform.Ratio)); payload = new byte[length]; Buffer.BlockCopy(zlibRxBuffer, 0, payload, 0, length); } // mac isn't encrypted, read directly from network stream byte[] mac = new byte[hmac.BlockSize]; st.Read(mac, 0, hmac.BlockSize); if (!hmac.IsMatch(mac)) { throw new CryptographicException("MAC couldn't be verified!"); } hmac.Reset(); p = PacketFactory.Create(session, payload); break; } } if (p.Code == MessageCode.SSH_MSG_IDENTIFICATION) { SocketModeRx = Mode.PlainText; } if (p.Code == MessageCode.SSH_MSG_NEWKEYS) { SocketModeRx = Mode.CipherText; } return(p); }