⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssh1connection.cs

📁 Granados是一个基于.NET的SSH客户端库。同时支持SSH1和SSH2。实现了AES, Blowfish, TripleDES, RSA, DSA等加密验证算法。实现TCP协议连接。
💻 CS
📖 第 1 页 / 共 2 页
字号:
/* ---------------------------------------------------------------------------
 *
 * Copyright (c) Routrek Networks, Inc.    All Rights Reserved..
 * 
 * This file is a part of the Granados SSH Client Library that is subject to
 * the license included in the distributed package.
 * You may not use this file except in compliance with the license.
 * 
 * ---------------------------------------------------------------------------
 */
using System;
using System.IO;
using System.Security.Cryptography;
using System.Net.Sockets;
using System.Text;
using System.Diagnostics;

using Routrek.PKI;
using Routrek.SSHC;
using Routrek.Toolkit;

namespace Routrek.SSHCV1
{
	public sealed class SSH1Connection : SSHConnection {
	
		private const int AUTH_NOT_REQUIRED = 0;
		private const int AUTH_REQUIRED = 1;

		private SSH1ConnectionInfo _cInfo;
		private int _shellID;

		private SSH1PacketBuilder _packetBuilder;
		private bool _executingShell;
		

		public SSH1Connection(SSHConnectionParameter param, ISSHConnectionEventReceiver er, string serverversion, string clientversion) : base(param, er) {
			_cInfo = new SSH1ConnectionInfo();
			_cInfo._serverVersionString = serverversion;
			_cInfo._clientVersionString = clientversion;
			_shellID = -1;
			_packetBuilder = new SSH1PacketBuilder(new SynchronizedSSH1PacketHandler());
		}
		public override SSHConnectionInfo ConnectionInfo {
			get {
				return _cInfo;
			}
		}
		internal override IByteArrayHandler PacketBuilder {
			get {
				return _packetBuilder;
			}
		}
		public override int ChannelCount {
			get {
				return base.ChannelCount + 1; //'1' is for the shell
			}
		}

		internal override AuthenticationResult Connect(AbstractSocket s) {
			_stream = s;
			
			// Phase2 receives server keys
			ReceiveServerKeys();
			if(_param.KeyCheck!=null && !_param.KeyCheck(_cInfo)) {
				_stream.Close();
				return AuthenticationResult.Failure;
			}

			// Phase3 generates session key
			byte[] session_key = GenerateSessionKey();
			
			// Phase4 establishes the session key
			try {
				_packetBuilder.SetSignal(false);
				SendSessionKey(session_key);
				InitCipher(session_key);
			}
			finally {
				_packetBuilder.SetSignal(true);
			}
			ReceiveKeyConfirmation();
			
			// Phase5 user authentication
			SendUserName(_param.UserName);
			if(ReceiveAuthenticationRequirement()==AUTH_REQUIRED) {
				if(_param.AuthenticationType==AuthenticationType.Password) {
					SendPlainPassword();
				} else if(_param.AuthenticationType==AuthenticationType.PublicKey) {
					DoRSAChallengeResponse();
				}
				bool auth = ReceiveAuthenticationResult();
				if(!auth) throw new SSHException(Strings.GetString("AuthenticationFailed"));

			}
			
			_packetBuilder.Handler = new CallbackSSH1PacketHandler(this);
			return AuthenticationResult.Success;
		}

		internal void Transmit(SSH1Packet p) {
			lock(this) {
				p.WriteTo(_stream, _tCipher);
			}
		}

		public override void Disconnect(string msg) {
			if(_closed) return;
			SSH1DataWriter w = new SSH1DataWriter();
			w.Write(msg);
			SSH1Packet p = SSH1Packet.FromPlainPayload(PacketType.SSH_MSG_DISCONNECT, w.ToByteArray());
			p.WriteTo(_stream, _tCipher);
			_stream.Flush();
			_closed = true;
			_stream.Close();
		}

		public override void Close() {
			if(_closed) return;
			_closed = true;
			_stream.Close();
		} 

		public override void SendIgnorableData(string msg) {
			SSH1DataWriter w = new SSH1DataWriter();
			w.Write(msg);
			SSH1Packet p = SSH1Packet.FromPlainPayload(PacketType.SSH_MSG_IGNORE, w.ToByteArray());
			Transmit(p);
		}

	
		private void ReceiveServerKeys() {
			SSH1Packet SSH1Packet = ReceivePacket();
			if(SSH1Packet.Type!=PacketType.SSH_SMSG_PUBLIC_KEY) throw new SSHException("unexpected SSH SSH1Packet type " + SSH1Packet.Type, SSH1Packet.Data);
			
			SSH1DataReader reader = new SSH1DataReader(SSH1Packet.Data);
			_cInfo._serverinfo = new SSHServerInfo(reader); 
			_cInfo._hostkey = new RSAPublicKey(_cInfo._serverinfo.host_key_public_exponent, _cInfo._serverinfo.host_key_public_modulus);
			
			//read protocol support parameters
			int protocol_flags = reader.ReadInt32();
			int supported_ciphers_mask = reader.ReadInt32();
			_cInfo.SetSupportedCipherAlgorithms(supported_ciphers_mask);
			int supported_authentications_mask = reader.ReadInt32();
			//Debug.WriteLine(String.Format("ServerOptions {0} {1} {2}", protocol_flags, supported_ciphers_mask, supported_authentications_mask));

			if(reader.Rest>0) throw new SSHException("data length mismatch", SSH1Packet.Data);
			
			//Debug Info
			/*
			System.out.println("Flags="+protocol_flags);
			System.out.println("Cipher="+supported_ciphers_mask);
			System.out.println("Auth="+supported_authentications_mask);
			*/
			
			bool found = false;
			foreach(CipherAlgorithm a in _param.PreferableCipherAlgorithms) {
				if(a!=CipherAlgorithm.Blowfish && a!=CipherAlgorithm.TripleDES)
					continue;
				else if(a==CipherAlgorithm.Blowfish && (supported_ciphers_mask & (1 << (int)CipherAlgorithm.Blowfish))==0)
					continue; 
				else if(a==CipherAlgorithm.TripleDES && (supported_ciphers_mask & (1 << (int)CipherAlgorithm.TripleDES))==0)
					continue; 

				_cInfo._algorithmForReception = _cInfo._algorithmForTransmittion = a;  
				found = true;
				break;
			}

			if(!found) 
				throw new SSHException(String.Format(Strings.GetString("ServerNotSupportedX"), "Blowfish/TripleDES"));

			if(_param.AuthenticationType==AuthenticationType.Password && (supported_authentications_mask & (1 << (int)AuthenticationType.Password))==0)
				throw new SSHException(String.Format(Strings.GetString("ServerNotSupportedPassword")), SSH1Packet.Data);
			if(_param.AuthenticationType==AuthenticationType.PublicKey && (supported_authentications_mask & (1 << (int)AuthenticationType.PublicKey))==0)
				throw new SSHException(String.Format(Strings.GetString("ServerNotSupportedRSA")), SSH1Packet.Data);
		}
	
		private byte[] GenerateSessionKey() {
			//session key(256bits)
			byte[] session_key = new byte[32];
			_param.Random.NextBytes(session_key); 
			//for(int i=0; i<32; i++) Debug.Write(String.Format("0x{0:x}, ", session_key[i]));
			
			return session_key;
		}
	
		private void SendSessionKey(byte[] session_key) {
			try
			{
				//step1 XOR with session_id
				byte[] working_data = new byte[session_key.Length];
				byte[] session_id = CalcSessionID();
				Array.Copy(session_key, 0, working_data, 0, session_key.Length);
				for(int i=0; i<session_id.Length; i++) working_data[i] ^= session_id[i];

				//step2 decrypts with RSA
				RSAPublicKey first_encryption;
				RSAPublicKey second_encryption;
				SSHServerInfo si = _cInfo._serverinfo;
				int first_key_bytelen, second_key_bytelen;
				if(si.server_key_bits < si.host_key_bits)
				{
					first_encryption  = new RSAPublicKey(si.server_key_public_exponent, si.server_key_public_modulus);
					second_encryption = new RSAPublicKey(si.host_key_public_exponent, si.host_key_public_modulus);
					first_key_bytelen = (si.server_key_bits+7)/8;
					second_key_bytelen = (si.host_key_bits+7)/8;
				}
				else
				{
					first_encryption  = new RSAPublicKey(si.host_key_public_exponent, si.host_key_public_modulus);
					second_encryption = new RSAPublicKey(si.server_key_public_exponent, si.server_key_public_modulus);
					first_key_bytelen = (si.host_key_bits+7)/8;
					second_key_bytelen = (si.server_key_bits+7)/8;
				}

				BigInteger first_result = RSAUtil.PKCS1PadType2(new BigInteger(working_data), first_key_bytelen, _param.Random).modPow(first_encryption.Exponent, first_encryption.Modulus);
				BigInteger second_result = RSAUtil.PKCS1PadType2(first_result, second_key_bytelen, _param.Random).modPow(second_encryption.Exponent, second_encryption.Modulus);

				//output
				SSH1DataWriter writer = new SSH1DataWriter();
				writer.Write((byte)_cInfo._algorithmForTransmittion);
				writer.Write(si.anti_spoofing_cookie);
				writer.Write(second_result);
				writer.Write(0); //protocol flags

				//send
				SSH1Packet SSH1Packet = SSH1Packet.FromPlainPayload(PacketType.SSH_CMSG_SESSION_KEY, writer.ToByteArray());
				SSH1Packet.WriteTo(_stream);

				_sessionID = session_id;

			}
			catch(Exception e)
			{
				if(e is IOException)
					throw (IOException)e;
				else
				{
					string t = e.StackTrace;
					throw new SSHException(e.Message); //IOException埲奜偼傒側SSHException偵偟偰偟傑偆
				}
			}
		}
	
		private void ReceiveKeyConfirmation() {
			SSH1Packet SSH1Packet = ReceivePacket();
			if(SSH1Packet.Type!=PacketType.SSH_SMSG_SUCCESS)
				throw new SSHException("unexpected packet type [" + SSH1Packet.Type +"] at ReceiveKeyConfirmation()", SSH1Packet.Data);
		}
	
		private int ReceiveAuthenticationRequirement() {
			SSH1Packet SSH1Packet = ReceivePacket();
			if(SSH1Packet.Type==PacketType.SSH_SMSG_SUCCESS)
				return AUTH_NOT_REQUIRED;
			else if(SSH1Packet.Type==PacketType.SSH_SMSG_FAILURE)
				return AUTH_REQUIRED;  
			else
				throw new SSHException("type " + SSH1Packet.Type, SSH1Packet.Data);
		}
	
		private void SendUserName(string username) {
			SSH1DataWriter writer = new SSH1DataWriter();
			writer.Write(username);
			SSH1Packet SSH1Packet = SSH1Packet.FromPlainPayload(PacketType.SSH_CMSG_USER, writer.ToByteArray());
			SSH1Packet.WriteTo(_stream, _tCipher);
		}
		private void SendPlainPassword() {
			SSH1DataWriter writer = new SSH1DataWriter();
			writer.Write(_param.Password);
			SSH1Packet SSH1Packet = SSH1Packet.FromPlainPayload(PacketType.SSH_CMSG_AUTH_PASSWORD, writer.ToByteArray());
			SSH1Packet.WriteTo(_stream, _tCipher);
		}

		//RSA authentication
		private void DoRSAChallengeResponse() {
			//read key
			SSH1UserAuthKey key = new SSH1UserAuthKey(_param.IdentityFile, _param.Password);
			SSH1DataWriter w = new SSH1DataWriter();
			w.Write(key.PublicModulus);
			SSH1Packet p = SSH1Packet.FromPlainPayload(PacketType.SSH_CMSG_AUTH_RSA, w.ToByteArray());
			p.WriteTo(_stream, _tCipher);

			p = ReceivePacket();
			if(p.Type==PacketType.SSH_SMSG_FAILURE)
				throw new SSHException(Strings.GetString("ServerRefusedRSA"));
			else if(p.Type!=PacketType.SSH_SMSG_AUTH_RSA_CHALLENGE)
				throw new SSHException(String.Format(Strings.GetString("UnexpectedResponse"), p.Type));

			//creating challenge
			SSH1DataReader r = new SSH1DataReader(p.Data);
			BigInteger challenge = key.decryptChallenge(r.ReadMPInt());
			byte[] rawchallenge = RSAUtil.StripPKCS1Pad(challenge, 2).getBytes();

			//building response
			MemoryStream bos = new MemoryStream();
			bos.Write(rawchallenge, 0, rawchallenge.Length); //!!mindterm偱偼摢偑侽偐偳偆偐偱曄側僴儞僪儕儞僌偑偁偭偨
			bos.Write(_sessionID, 0, _sessionID.Length);
			byte[] response = new MD5CryptoServiceProvider().ComputeHash(bos.ToArray());

			w = new SSH1DataWriter();
			w.Write(response);
			p = SSH1Packet.FromPlainPayload(PacketType.SSH_CMSG_AUTH_RSA_RESPONSE, w.ToByteArray());
			p.WriteTo(_stream, _tCipher);

		}

		private bool ReceiveAuthenticationResult() {
			SSH1Packet SSH1Packet = ReceivePacket();
			PacketType type = SSH1Packet.Type;
			if(type==PacketType.SSH_MSG_DEBUG) {
				SSH1DataReader r = new SSH1DataReader(SSH1Packet.Data);
				//Debug.WriteLine("receivedd debug message:"+Encoding.ASCII.GetString(r.ReadString()));
				return ReceiveAuthenticationResult();
			}
			else if(type==PacketType.SSH_SMSG_SUCCESS)
				return true;
			else if(type==PacketType.SSH_SMSG_FAILURE)
				return false;
			else
				throw new SSHException("type: " + type, SSH1Packet.Data);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -