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

Telnet服务器

开发平台:

C#

  1. /*
  2.  Copyright (c) 2005 Poderosa Project, All Rights Reserved.
  3.  This file is a part of the Granados SSH Client Library that is subject to
  4.  the license included in the distributed package.
  5.  You may not use this file except in compliance with the license.
  6.  $Id: SSH1Packet.cs,v 1.2 2005/04/20 08:58:56 okajima Exp $
  7. */
  8. /*
  9. * structure of packet
  10. * length(4) padding(1-8) type(1) data(0+) crc(4)    
  11. * 1. length = type+data+crc
  12. * 2. the length of padding+type+data+crc must be a multiple of 8
  13. * 3. padding length must be 1 at least
  14. * 4. crc is calculated from padding,type and data
  15. *
  16.  */
  17. using System;
  18. using System.Collections;
  19. using System.Diagnostics;
  20. using System.Threading;
  21. using Granados.Crypto;
  22. using Granados.SSHC;
  23. namespace Granados.SSHCV1
  24. {
  25. internal class SSH1Packet
  26. {
  27. private byte _type;
  28. private byte[] _data;
  29. private uint _CRC;
  30. /**
  31. * reads type, data, and crc from byte array.
  32. * an exception is thrown if crc check fails.
  33. */
  34. internal void ConstructAndCheck(byte[] buf, int packet_length, int padding_length, bool check_crc) {
  35. _type = buf[padding_length];
  36. //System.out.println("Type: " + _type);
  37. if(packet_length > 5) //the body is not empty
  38. {
  39. _data = new byte[packet_length-5]; //5 is the length of [type] and [crc]
  40. Array.Copy(buf, padding_length+1, _data, 0, packet_length-5);
  41. }
  42. _CRC = (uint)SSHUtil.ReadInt32(buf, buf.Length-4);
  43. if(check_crc) {
  44. uint c = CRC.Calc(buf, 0, buf.Length-4);
  45. if(_CRC != c)
  46. throw new SSHException("CRC Error", buf);
  47. }
  48. }
  49. /**
  50. * constructs from the packet type and the body
  51. */
  52. public static SSH1Packet FromPlainPayload(PacketType type, byte[] data) {
  53. SSH1Packet p = new SSH1Packet();
  54. p._type = (byte)type;
  55. p._data = data;
  56. return p;
  57. }
  58. public static SSH1Packet FromPlainPayload(PacketType type) {
  59. SSH1Packet p = new SSH1Packet();
  60. p._type = (byte)type;
  61. p._data = new byte[0];
  62. return p;
  63. }
  64. /**
  65. * creates a packet as the input of shell
  66. */
  67. static SSH1Packet AsStdinString(byte[] input) {
  68. SSH1DataWriter w = new SSH1DataWriter();
  69. w.WriteAsString(input);
  70. SSH1Packet p = SSH1Packet.FromPlainPayload(PacketType.SSH_CMSG_STDIN_DATA, w.ToByteArray());
  71. return p;
  72. }
  73. private byte[] BuildImage() {
  74. int packet_length = (_data==null? 0 : _data.Length) + 5; //type and CRC
  75. int padding_length = 8 - (packet_length % 8);
  76. byte[] image = new byte[packet_length + padding_length + 4];
  77. SSHUtil.WriteIntToByteArray(image, 0, packet_length);
  78. for(int i=0; i<padding_length; i++) image[4+i]=0; //padding: filling by random values is better
  79. image[4+padding_length] = _type;
  80. if(_data!=null)
  81. Array.Copy(_data, 0, image, 4+padding_length+1, _data.Length);
  82. _CRC = CRC.Calc(image, 4, image.Length-8);
  83. SSHUtil.WriteIntToByteArray(image, image.Length-4, (int)_CRC);
  84. return image;
  85. }
  86. /**
  87. * writes to plain stream
  88. */
  89. public void WriteTo(AbstractSocket output) {
  90. byte[] image = BuildImage();
  91. output.Write(image, 0, image.Length);
  92. }
  93. /**
  94. * writes to encrypted stream
  95. */
  96. public void WriteTo(AbstractSocket output, Cipher cipher) {
  97. byte[] image = BuildImage();
  98. //dumpBA(image);
  99. byte[] encrypted = new byte[image.Length-4];
  100. cipher.Encrypt(image, 4, image.Length-4, encrypted, 0); //length field must not be encrypted
  101. Array.Copy(encrypted, 0, image, 4, encrypted.Length);
  102. output.Write(image, 0, image.Length);
  103. }
  104. public PacketType Type {
  105. get {
  106. return (PacketType)_type;
  107. }
  108. }
  109. public byte[] Data {
  110. get {
  111. return _data;
  112. }
  113. }
  114. public int DataLength {
  115. get {
  116. return _data==null? 0 : _data.Length;
  117. }
  118. }
  119. }
  120. internal interface ISSH1PacketHandler : IHandlerBase {
  121. void OnPacket(SSH1Packet packet);
  122. }
  123. internal class SynchronizedSSH1PacketHandler : SynchronizedHandlerBase, ISSH1PacketHandler {
  124. internal ArrayList _packets;
  125. internal SynchronizedSSH1PacketHandler() {
  126. _packets = new ArrayList();
  127. }
  128. public void OnPacket(SSH1Packet packet) {
  129. lock(this) {
  130. _packets.Add(packet);
  131. if(_packets.Count > 0)
  132. SetReady();
  133. }
  134. }
  135. public void OnError(Exception error, string msg) {
  136. base.SetError(msg);
  137. }
  138. public void OnClosed() {
  139. base.SetClosed();
  140. }
  141. public bool HasPacket {
  142. get {
  143. return _packets.Count>0;
  144. }
  145. }
  146. public SSH1Packet PopPacket() {
  147. lock(this) {
  148. if(_packets.Count==0)
  149. return null;
  150. else {
  151. SSH1Packet p = null;
  152. p = (SSH1Packet)_packets[0];
  153. _packets.RemoveAt(0);
  154. if(_packets.Count==0) _event.Reset();
  155. return p;
  156. }
  157. }
  158. }
  159. }
  160. internal class CallbackSSH1PacketHandler : ISSH1PacketHandler {
  161. internal SSH1Connection _connection;
  162. internal CallbackSSH1PacketHandler(SSH1Connection con) {
  163. _connection = con;
  164. }
  165. public void OnPacket(SSH1Packet packet) {
  166. _connection.AsyncReceivePacket(packet);
  167. }
  168. public void OnError(Exception error, string msg) {
  169. _connection.EventReceiver.OnError(error, msg);
  170. }
  171. public void OnClosed() {
  172. _connection.EventReceiver.OnConnectionClosed();
  173. }
  174. }
  175. internal class SSH1PacketBuilder : IByteArrayHandler {
  176. private ISSH1PacketHandler _handler;
  177. private byte[] _buffer;
  178. private int _readOffset;
  179. private int _writeOffset;
  180. private Cipher _cipher;
  181. private bool _checkMAC;
  182. private ManualResetEvent _event;
  183. public SSH1PacketBuilder(ISSH1PacketHandler handler) {
  184. _handler = handler;
  185. _buffer = new byte[0x1000];
  186. _readOffset = 0;
  187. _writeOffset = 0;
  188. _cipher = null;
  189. _checkMAC = false;
  190. _event = null;
  191. }
  192. public void SetSignal(bool value) {
  193. if(_event==null) _event = new ManualResetEvent(true);
  194. if(value)
  195. _event.Set();
  196. else
  197. _event.Reset();
  198. }
  199. public void SetCipher(Cipher c, bool check_mac) {
  200. _cipher = c;
  201. _checkMAC = check_mac;
  202. }
  203. public ISSH1PacketHandler Handler {
  204. get {
  205. return _handler;
  206. }
  207. set {
  208. _handler = value;
  209. }
  210. }
  211. public void OnData(byte[] data, int offset, int length) {
  212. try {
  213. while(_buffer.Length - _writeOffset < length)
  214. ExpandBuffer();
  215. Array.Copy(data, offset, _buffer, _writeOffset, length);
  216. _writeOffset += length;
  217. SSH1Packet p = ConstructPacket();
  218. while(p!=null) {
  219. _handler.OnPacket(p);
  220. p = ConstructPacket();
  221. }
  222. ReduceBuffer();
  223. }
  224. catch(Exception ex) {
  225. OnError(ex, ex.Message);
  226. }
  227. }
  228. //returns true if a new packet could be obtained
  229. private SSH1Packet ConstructPacket() {
  230. if(_event!=null && !_event.WaitOne(3000, false))
  231. throw new Exception("waithandle timed out");
  232. if(_writeOffset-_readOffset<4) return null;
  233. int packet_length = SSHUtil.ReadInt32(_buffer, _readOffset);
  234. int padding_length = 8 - (packet_length % 8); //padding length
  235. int total = packet_length + padding_length;
  236. if(_writeOffset-_readOffset<4+total) return null;
  237. byte[] decrypted = new byte[total];
  238. if(_cipher!=null)
  239. _cipher.Decrypt(_buffer, _readOffset+4, total, decrypted, 0);
  240. else
  241. Array.Copy(_buffer, _readOffset+4, decrypted, 0, total);
  242. _readOffset += 4 + total;
  243. SSH1Packet p = new SSH1Packet();
  244. p.ConstructAndCheck(decrypted, packet_length, padding_length, _checkMAC);
  245. return p;
  246. }
  247. private void ExpandBuffer() {
  248. byte[] t = new byte[_buffer.Length*2];
  249. Array.Copy(_buffer, 0, t, 0, _buffer.Length);
  250. _buffer = t;
  251. }
  252. private void ReduceBuffer() {
  253. if(_readOffset==_writeOffset) {
  254. _readOffset = 0;
  255. _writeOffset = 0;
  256. }
  257. else {
  258. byte[] temp = new byte[_writeOffset - _readOffset];
  259. Array.Copy(_buffer, _readOffset, temp, 0, temp.Length);
  260. Array.Copy(temp, 0, _buffer, 0, temp.Length);
  261. _readOffset = 0;
  262. _writeOffset = temp.Length;
  263. }
  264. }
  265. public void OnError(Exception error, string msg) {
  266. _handler.OnError(error, msg);
  267. }
  268. public void OnClosed() {
  269. _handler.OnClosed();
  270. if(_event!=null) _event.Close();
  271. }
  272. }
  273. }