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

📄 ssh2userauthkey.cs

📁 Granados是一个基于.NET的SSH客户端库。同时支持SSH1和SSH2。实现了AES, Blowfish, TripleDES, RSA, DSA等加密验证算法。实现TCP协议连接。
💻 CS
字号:
/* ---------------------------------------------------------------------------
 *
 * 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.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using Routrek.PKI;
using Routrek.SSHC;
using Routrek.Toolkit;

namespace Routrek.SSHCV2
{

	public class SSH2UserAuthKey {

		private const int MAGIC_VAL = 0x3f6ff9eb;

		private KeyPair _keypair;

		public SSH2UserAuthKey(KeyPair kp) {
			_keypair = kp;
		}

		public PublicKeyAlgorithm Algorithm {
			get {
				return _keypair.Algorithm;
			}
		}
		public KeyPair KeyPair {
			get {
				return _keypair;
			}
		}

		public byte[] Sign(byte[] data) {
			PublicKeyAlgorithm a = _keypair.Algorithm;
			if(a==PublicKeyAlgorithm.RSA)
				return ((RSAKeyPair)_keypair).SignWithSHA1(data);
			else
				return ((DSAKeyPair)_keypair).Sign(new SHA1CryptoServiceProvider().ComputeHash(data));
		}
		public byte[] GetPublicKeyBlob() {
			SSH2DataWriter w = new SSH2DataWriter();
			w.Write(SSH2Util.PublicKeyAlgorithmName(_keypair.Algorithm));
			_keypair.PublicKey.WriteTo(w);
			return w.ToByteArray();
		}
		

		public static byte[] PassphraseToKey(string passphrase, int length) {
			MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
			byte[] pp = Encoding.UTF8.GetBytes(passphrase);
			int hashlen = md5.HashSize/8;
			byte[] buf = new byte[((length + hashlen) / hashlen) * hashlen];
			int offset = 0;
			
			while(offset < length) {
				MemoryStream s = new MemoryStream();
				s.Write(pp, 0, pp.Length);
				if(offset > 0) s.Write(buf, 0, offset);
				Array.Copy(md5.ComputeHash(s.ToArray()), 0, buf, offset, hashlen);
				offset += hashlen;
				md5.Initialize();
			}

			byte[] key = new byte[length];
			Array.Copy(buf, 0, key, 0, length);
			return key;
		}

		/*
		 * Format style note
		 *  ---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
		 *  Comment: *******
		 *  <base64-encoded body>
		 *  ---- END SSH2 ENCRYPTED PRIVATE KEY ----
		 * 
		 *  body = MAGIC_VAL || body-length || type(string) || encryption-algorithm-name(string) || encrypted-body(string)
		 *  encrypted-body = array of BigInteger(algorithm-specific)
		 */ 
		public static SSH2UserAuthKey FromSECSHStyleStream(Stream strm, string passphrase) {
			StreamReader r = new StreamReader(strm, Encoding.ASCII);
			string l = r.ReadLine();
			if(l==null || l!="---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----") throw new SSHException("Wrong key format");

			l = r.ReadLine();
			StringBuilder buf = new StringBuilder();
			while(l!="---- END SSH2 ENCRYPTED PRIVATE KEY ----") {
				if(l.IndexOf(':')==-1)
					buf.Append(l);
				else {
					while(l.EndsWith("\\")) l = r.ReadLine();
				}
				l = r.ReadLine();
				if(l==null) throw new SSHException("Key is broken");
			}
			r.Close();

			byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(buf.ToString()));
			//Debug.WriteLine(DebugUtil.DumpByteArray(keydata));

			/*
			FileStream fs = new FileStream("C:\\IOPort\\keydata1.bin", FileMode.Create);
			fs.Write(keydata, 0, keydata.Length);
			fs.Close();
			*/

			SSH2DataReader re = new SSH2DataReader(keydata);
			int    magic         = re.ReadInt32();
			if(magic!=MAGIC_VAL) throw new SSHException("key file is broken");
			int    privateKeyLen = re.ReadInt32();
			string type          = Encoding.ASCII.GetString(re.ReadString());

			string ciphername    = Encoding.ASCII.GetString(re.ReadString());
			int    bufLen        = re.ReadInt32();
			if(ciphername!="none") {
				CipherAlgorithm algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
				byte[] key = PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
				Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
				byte[] tmp = new Byte[re.Image.Length-re.Offset];
				c.Decrypt(re.Image, re.Offset, re.Image.Length-re.Offset, tmp, 0);
				re = new SSH2DataReader(tmp);
			}

			int parmLen          = re.ReadInt32();
			if(parmLen<0 || parmLen>re.Rest)
				throw new SSHException(Strings.GetString("WrongPassphrase"));

			if(type.IndexOf("if-modn")!=-1) {
				//mindterm mistaken this order of BigIntegers
				BigInteger e = re.ReadBigIntWithBits();
				BigInteger d = re.ReadBigIntWithBits();
				BigInteger n = re.ReadBigIntWithBits();
				BigInteger u = re.ReadBigIntWithBits();
				BigInteger p = re.ReadBigIntWithBits();
				BigInteger q = re.ReadBigIntWithBits();
				return new SSH2UserAuthKey(new RSAKeyPair(e, d, n, u, p, q));
			}
			else if(type.IndexOf("dl-modp")!=-1) {
				if(re.ReadInt32()!=0) throw new SSHException("DSS Private Key File is broken");
				BigInteger p = re.ReadBigIntWithBits();
				BigInteger g = re.ReadBigIntWithBits();
				BigInteger q = re.ReadBigIntWithBits();
				BigInteger y = re.ReadBigIntWithBits();
				BigInteger x = re.ReadBigIntWithBits();
				return new SSH2UserAuthKey(new DSAKeyPair(p, g, q, y, x));
			}
			else
				throw new SSHException("unknown authentication method "+type);

		}
		public static SSH2UserAuthKey FromSECSHStyleFile(string filename, string passphrase) {
			return FromSECSHStyleStream(new FileStream(filename, FileMode.Open, FileAccess.Read), passphrase);
		}

		public void WritePrivatePartInSECSHStyleFile(Stream dest, string comment, string passphrase) {
			
			//step1 key body
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.Write(0); //this field is filled later
			if(_keypair.Algorithm==PublicKeyAlgorithm.RSA) {
				RSAKeyPair rsa = (RSAKeyPair)_keypair;
				RSAPublicKey pub = (RSAPublicKey)_keypair.PublicKey;
				wr.WriteBigIntWithBits(pub.Exponent);
				wr.WriteBigIntWithBits(rsa.D);
				wr.WriteBigIntWithBits(pub.Modulus);
				wr.WriteBigIntWithBits(rsa.U);
				wr.WriteBigIntWithBits(rsa.P);
				wr.WriteBigIntWithBits(rsa.Q);
			}
			else {
				DSAKeyPair dsa = (DSAKeyPair)_keypair;
				DSAPublicKey pub = (DSAPublicKey)_keypair.PublicKey;
				wr.Write(0);
				wr.WriteBigIntWithBits(pub.P);
				wr.WriteBigIntWithBits(pub.G);
				wr.WriteBigIntWithBits(pub.Q);
				wr.WriteBigIntWithBits(pub.Y);
				wr.WriteBigIntWithBits(dsa.X);
			}

			int padding_len = 0;
			if(passphrase!=null) {
				padding_len = 8 - (int)wr.Length % 8;
				wr.Write(new byte[padding_len]);
			}
			byte[] encrypted_body = wr.ToByteArray();
			SSHUtil.WriteIntToByteArray(encrypted_body, 0, encrypted_body.Length - padding_len - 4);

			//encrypt if necessary
			if(passphrase!=null) {
				Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, CipherAlgorithm.TripleDES, PassphraseToKey(passphrase,24));
				Debug.Assert(encrypted_body.Length % 8 ==0);
				byte[] tmp = new Byte[encrypted_body.Length];
				c.Encrypt(encrypted_body, 0, encrypted_body.Length, tmp, 0);
				encrypted_body = tmp;
			}

			//step2 make binary key data
			wr = new SSH2DataWriter();
			wr.Write(MAGIC_VAL);
			wr.Write(0); //for total size
			wr.Write(_keypair.Algorithm==PublicKeyAlgorithm.RSA?
				"if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}" :
				"dl-modp{sign{dsa-nist-sha1},dh{plain}}");

			wr.Write(passphrase==null? "none" : "3des-cbc");
			wr.WriteAsString(encrypted_body);

			byte[] rawdata = wr.ToByteArray();
			SSHUtil.WriteIntToByteArray(rawdata, 4, rawdata.Length); //fix total length

			//step3 write final data
			StreamWriter sw = new StreamWriter(dest, Encoding.ASCII);
			sw.WriteLine("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----");
			if(comment!=null)
				WriteKeyFileBlock(sw, "Comment: " + comment, true);
			WriteKeyFileBlock(sw, Encoding.ASCII.GetString(Base64.Encode(rawdata)), false);
			sw.WriteLine("---- END SSH2 ENCRYPTED PRIVATE KEY ----");
			sw.Close();

		}

		public void WritePublicPartInSECSHStyle(Stream dest, string comment) {
			StreamWriter sw = new StreamWriter(dest, Encoding.ASCII);
			sw.WriteLine("---- BEGIN SSH2 PUBLIC KEY ----");
			if(comment!=null)
				WriteKeyFileBlock(sw, "Comment: " + comment, true);
			WriteKeyFileBlock(sw, FormatBase64EncodedPublicKeyBody(), false);
			sw.WriteLine("---- END SSH2 PUBLIC KEY ----");
			sw.Close();

		}
		public void WritePublicPartInOpenSSHStyle(Stream dest) {
			StreamWriter sw = new StreamWriter(dest, Encoding.ASCII);
			sw.Write(SSH2Util.PublicKeyAlgorithmName(_keypair.Algorithm));
			sw.Write(' ');
			sw.WriteLine(FormatBase64EncodedPublicKeyBody());
			sw.Close();
		}
		private string FormatBase64EncodedPublicKeyBody() {
			SSH2DataWriter wr = new SSH2DataWriter();
			wr.Write(SSH2Util.PublicKeyAlgorithmName(_keypair.Algorithm));
			_keypair.PublicKey.WriteTo(wr);
			
			return Encoding.ASCII.GetString(Base64.Encode(wr.ToByteArray()));
		}

		private static void WriteKeyFileBlock(StreamWriter sw, string data, bool escape_needed) {
			char[] d = data.ToCharArray();
			int cursor = 0;
			const int maxlen = 70;
			while(cursor < d.Length) {
				if(maxlen >= d.Length-cursor)
					sw.WriteLine(d, cursor, d.Length-cursor);
				else {
					if(escape_needed) {
						sw.Write(d, cursor, maxlen-1);
						sw.WriteLine('\\');
						cursor--;
					}
					else
						sw.WriteLine(d, cursor, maxlen);
				}

				cursor += maxlen;
			}
		}
	}

}

⌨️ 快捷键说明

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