SSH2Packet.cs
上传用户:szltgg
上传日期:2019-05-16
资源大小:604k
文件大小:9k
源码类别:

Telnet服务器

开发平台:

C#

  1. /* ---------------------------------------------------------------------------
  2.  *
  3.  * Copyright (c) Granados Networks, Inc.    All Rights Reserved..
  4.  * 
  5.  * This file is a part of the Granados SSH Client Library that is subject to
  6.  * the license included in the distributed package.
  7.  * You may not use this file except in compliance with the license.
  8.  * 
  9.  * $Id: SSH2Packet.cs,v 1.2 2005/04/20 09:00:56 okajima Exp $
  10.  */
  11. using System;
  12. using System.Collections;
  13. using System.IO;
  14. using System.Threading;
  15. using System.Diagnostics;
  16. using Granados.SSHC;
  17. namespace Granados.SSHCV2
  18. {
  19. /* SSH2 Packet Structure
  20.  * 
  21.  * uint32    packet_length
  22.      * byte      padding_length
  23.      * byte[n1]  payload; n1 = packet_length - padding_length - 1
  24.      * byte[n2]  random padding; n2 = padding_length (max 255)
  25.      * byte[m]   mac (message authentication code); m = mac_length
  26.  * 
  27.  * 4+1+n1+n2 must be a multiple of the cipher block size
  28.  */
  29. internal class SSH2Packet
  30. {
  31. private int _packetLength;
  32. private byte[] _payload;
  33. private byte[] _padding;
  34. private byte[] _mac;
  35. private const int MAX_PACKET_LENGTH = 0x80000; //there was the case that 64KB is insufficient
  36. public byte[] Data {
  37. get {
  38. return _payload;
  39. }
  40. }
  41. //constracts and appends mac
  42. public void CalcHash(MAC mac, int sequence) {
  43. byte[] buf = new byte[4+4+_packetLength];
  44. SSHUtil.WriteIntToByteArray(buf, 0, sequence);
  45. WriteTo(buf, 4, false);
  46. _mac = mac.Calc(buf);
  47. }
  48. public void WriteTo(AbstractSocket strm, Cipher cipher) {
  49. int bodylen = 4+_packetLength;
  50. byte[] buf = new byte[bodylen + (_mac==null? 0 : _mac.Length)];
  51. WriteTo(buf, 0, false);
  52. if(cipher!=null)
  53. cipher.Encrypt(buf, 0, bodylen, buf, 0);
  54. if(_mac!=null)
  55. Array.Copy(_mac, 0, buf, bodylen, _mac.Length);
  56. strm.Write(buf, 0, buf.Length);
  57. strm.Flush();
  58. }
  59. public void WriteTo(byte[] buf, int offset, bool includes_mac) {
  60. SSHUtil.WriteIntToByteArray(buf, offset, _packetLength);
  61. buf[offset+4] = (byte)_padding.Length;
  62. Array.Copy(_payload, 0, buf, offset+5, _payload.Length);
  63. Array.Copy(_padding, 0, buf, offset+5+_payload.Length, _padding.Length);
  64. if(includes_mac && _mac!=null)
  65. Array.Copy(_mac, 0, buf, offset+5+_payload.Length+_padding.Length, _mac.Length);
  66. }
  67. public static SSH2Packet FromPlainPayload(byte[] payload, int blocksize, Random rnd) {
  68. SSH2Packet p = new SSH2Packet();
  69. int r = 11 - payload.Length % blocksize;
  70. while(r < 4) r += blocksize;
  71. p._padding = new byte[r]; //block size is 8, and padding length is at least 4 bytes
  72. rnd.NextBytes(p._padding);
  73. p._payload = payload;
  74. p._packetLength = 1+payload.Length+p._padding.Length;
  75. return p;
  76. }
  77. //no decryption, no mac
  78. public static SSH2Packet FromPlainStream(byte[] buffer, int offset) {
  79. SSH2Packet p = new SSH2Packet();
  80. p._packetLength = SSHUtil.ReadInt32(buffer, offset);
  81. if(p._packetLength<=0 || p._packetLength>=MAX_PACKET_LENGTH) throw new SSHException(String.Format("packet size {0} is invalid", p._packetLength));
  82. offset += 4;
  83. byte pl = buffer[offset++];
  84. if(pl < 4) throw new SSHException(String.Format("padding length {0} is invalid", pl));
  85. p._payload = new byte[p._packetLength - 1 - pl];
  86. Array.Copy(buffer, offset, p._payload, 0, p._payload.Length);
  87. return p;
  88. }
  89. public static SSH2Packet FromDecryptedHead(byte[] head, byte[] buffer, int offset, Cipher cipher, int sequence, MAC mac) {
  90. SSH2Packet p = new SSH2Packet();
  91. p._packetLength = SSHUtil.ReadInt32(head, 0);
  92. if(p._packetLength<=0 || p._packetLength>=MAX_PACKET_LENGTH) throw new SSHException(String.Format("packet size {0} is invalid", p._packetLength));
  93. SSH2DataWriter buf = new SSH2DataWriter();
  94. buf.Write(sequence);
  95. buf.Write(head);
  96. if(p._packetLength > (cipher.BlockSize - 4)) {
  97. byte[] tmp = new byte[p._packetLength-(cipher.BlockSize - 4)];
  98. cipher.Decrypt(buffer, offset, tmp.Length, tmp, 0);
  99. offset += tmp.Length;
  100. buf.Write(tmp);
  101. }
  102. byte[] result = buf.ToByteArray();
  103. int padding_len = (int)result[8];
  104. if(padding_len<4) throw new SSHException("padding length is invalid");
  105. byte[] payload = new byte[result.Length-9-padding_len];
  106. Array.Copy(result, 9, payload, 0, payload.Length);
  107. p._payload = payload;
  108. if(mac!=null) {
  109. p._mac = mac.Calc(result);
  110. if(SSHUtil.memcmp(p._mac, 0, buffer, offset, mac.Size)!=0)
  111. throw new SSHException("MAC Error");
  112. }
  113. return p;
  114. }
  115. }
  116. internal interface ISSH2PacketHandler : IHandlerBase {
  117. void OnPacket(SSH2Packet packet);
  118. }
  119. internal class SynchronizedSSH2PacketHandler : SynchronizedHandlerBase, ISSH2PacketHandler {
  120. internal ArrayList _packets;
  121. internal SynchronizedSSH2PacketHandler() {
  122. _packets = new ArrayList();
  123. }
  124. public void OnPacket(SSH2Packet packet) {
  125. lock(this) {
  126. _packets.Add(packet);
  127. if(_packets.Count > 0)
  128. SetReady();
  129. }
  130. }
  131. public void OnError(Exception error, string msg) {
  132. base.SetError(msg);
  133. }
  134. public void OnClosed() {
  135. base.SetClosed();
  136. }
  137. public bool HasPacket {
  138. get {
  139. return _packets.Count>0;
  140. }
  141. }
  142. public SSH2Packet PopPacket() {
  143. lock(this) {
  144. if(_packets.Count==0)
  145. return null;
  146. else {
  147. SSH2Packet p = null;
  148. p = (SSH2Packet)_packets[0];
  149. _packets.RemoveAt(0);
  150. if(_packets.Count==0) _event.Reset();
  151. return p;
  152. }
  153. }
  154. }
  155. }
  156. internal class CallbackSSH2PacketHandler : ISSH2PacketHandler {
  157. internal SSH2Connection _connection;
  158. internal CallbackSSH2PacketHandler(SSH2Connection con) {
  159. _connection = con;
  160. }
  161. public void OnPacket(SSH2Packet packet) {
  162. _connection.AsyncReceivePacket(packet);
  163. }
  164. public void OnError(Exception error, string msg) {
  165. _connection.EventReceiver.OnError(error, msg);
  166. }
  167. public void OnClosed() {
  168. _connection.EventReceiver.OnConnectionClosed();
  169. }
  170. }
  171. internal class SSH2PacketBuilder : IByteArrayHandler {
  172. private ISSH2PacketHandler _handler;
  173. private byte[] _buffer;
  174. private byte[] _head;
  175. private int _readOffset;
  176. private int _writeOffset;
  177. private int _sequence;
  178. private Cipher _cipher;
  179. private MAC _mac;
  180. private ManualResetEvent _event;
  181. public SSH2PacketBuilder(ISSH2PacketHandler handler) {
  182. _handler = handler;
  183. _buffer = new byte[0x1000];
  184. _readOffset = 0;
  185. _writeOffset = 0;
  186. _sequence = 0;
  187. _cipher = null;
  188. _mac = null;
  189. _head = null;
  190. }
  191. public void SetSignal(bool value) {
  192. if(_event==null) _event = new ManualResetEvent(true);
  193. if(value)
  194. _event.Set();
  195. else
  196. _event.Reset();
  197. }
  198. public void SetCipher(Cipher c, MAC m) {
  199. _cipher = c;
  200. _mac = m;
  201. }
  202. public ISSH2PacketHandler Handler {
  203. get {
  204. return _handler;
  205. }
  206. set {
  207. _handler = value;
  208. }
  209. }
  210. public void OnData(byte[] data, int offset, int length) {
  211. try {
  212. while(_buffer.Length - _writeOffset < length)
  213. ExpandBuffer();
  214. Array.Copy(data, offset, _buffer, _writeOffset, length);
  215. _writeOffset += length;
  216. SSH2Packet p = ConstructPacket();
  217. while(p!=null) {
  218. _handler.OnPacket(p);
  219. p = ConstructPacket();
  220. }
  221. ReduceBuffer();
  222. }
  223. catch(Exception ex) {
  224. OnError(ex, ex.Message);
  225. }
  226. }
  227. //returns true if a new packet could be obtained
  228. private SSH2Packet ConstructPacket() {
  229. SSH2Packet packet = null;
  230. if(_event!=null && !_event.WaitOne(3000, false))
  231. throw new Exception("waithandle timed out");
  232. if(_cipher==null) {
  233. if(_writeOffset-_readOffset<4) return null;
  234. int len = SSHUtil.ReadInt32(_buffer, _readOffset);
  235. if(_writeOffset-_readOffset<4+len) return null;
  236. packet = SSH2Packet.FromPlainStream(_buffer, _readOffset);
  237. _readOffset += 4 + len;
  238. _sequence++;
  239. }
  240. else {
  241. if(_head==null) {
  242. if(_writeOffset-_readOffset<_cipher.BlockSize) return null;
  243. _head = new byte[_cipher.BlockSize];
  244. byte[] eh = new byte[_cipher.BlockSize];
  245. Array.Copy(_buffer, _readOffset, eh, 0, eh.Length);
  246. _readOffset += eh.Length;
  247. _cipher.Decrypt(eh, 0, eh.Length, _head, 0);
  248. }
  249. int len = SSHUtil.ReadInt32(_head, 0);
  250. if(_writeOffset-_readOffset < len+4-_head.Length+_mac.Size) return null;
  251. packet = SSH2Packet.FromDecryptedHead(_head, _buffer, _readOffset, _cipher, _sequence++, _mac);
  252. _readOffset += 4 + len - _head.Length + _mac.Size;
  253. _head = null;
  254. }
  255. return packet;
  256. }
  257. private void ExpandBuffer() {
  258. byte[] t = new byte[_buffer.Length*2];
  259. Array.Copy(_buffer, 0, t, 0, _buffer.Length);
  260. _buffer = t;
  261. }
  262. private void ReduceBuffer() {
  263. if(_readOffset==_writeOffset) {
  264. _readOffset = 0;
  265. _writeOffset = 0;
  266. }
  267. else {
  268. byte[] temp = new byte[_writeOffset - _readOffset];
  269. Array.Copy(_buffer, _readOffset, temp, 0, temp.Length);
  270. Array.Copy(temp, 0, _buffer, 0, temp.Length);
  271. _readOffset = 0;
  272. _writeOffset = temp.Length;
  273. }
  274. }
  275. public void OnError(Exception error, string msg) {
  276. _handler.OnError(error, msg);
  277. }
  278. public void OnClosed() {
  279. _handler.OnClosed();
  280. if(_event!=null) _event.Close();
  281. }
  282. }
  283. }