SSH2UserAuthKey.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: SSH2UserAuthKey.cs,v 1.2 2005/04/20 09:00:56 okajima Exp $
  10.  */
  11. using System;
  12. using System.Diagnostics;
  13. using System.IO;
  14. using System.Security.Cryptography;
  15. using System.Text;
  16. using Granados.PKI;
  17. using Granados.SSHC;
  18. using Granados.Toolkit;
  19. namespace Granados.SSHCV2
  20. {
  21. public class SSH2UserAuthKey {
  22. private const int MAGIC_VAL = 0x3f6ff9eb;
  23. private KeyPair _keypair;
  24. public SSH2UserAuthKey(KeyPair kp) {
  25. _keypair = kp;
  26. }
  27. public PublicKeyAlgorithm Algorithm {
  28. get {
  29. return _keypair.Algorithm;
  30. }
  31. }
  32. public KeyPair KeyPair {
  33. get {
  34. return _keypair;
  35. }
  36. }
  37. public byte[] Sign(byte[] data) {
  38. PublicKeyAlgorithm a = _keypair.Algorithm;
  39. if(a==PublicKeyAlgorithm.RSA)
  40. return ((RSAKeyPair)_keypair).SignWithSHA1(data);
  41. else
  42. return ((DSAKeyPair)_keypair).Sign(new SHA1CryptoServiceProvider().ComputeHash(data));
  43. }
  44. public byte[] GetPublicKeyBlob() {
  45. SSH2DataWriter w = new SSH2DataWriter();
  46. w.Write(SSH2Util.PublicKeyAlgorithmName(_keypair.Algorithm));
  47. _keypair.PublicKey.WriteTo(w);
  48. return w.ToByteArray();
  49. }
  50. public static byte[] PassphraseToKey(string passphrase, int length) {
  51. MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
  52. byte[] pp = Encoding.UTF8.GetBytes(passphrase);
  53. int hashlen = md5.HashSize/8;
  54. byte[] buf = new byte[((length + hashlen) / hashlen) * hashlen];
  55. int offset = 0;
  56. while(offset < length) {
  57. MemoryStream s = new MemoryStream();
  58. s.Write(pp, 0, pp.Length);
  59. if(offset > 0) s.Write(buf, 0, offset);
  60. Array.Copy(md5.ComputeHash(s.ToArray()), 0, buf, offset, hashlen);
  61. offset += hashlen;
  62. md5.Initialize();
  63. }
  64. byte[] key = new byte[length];
  65. Array.Copy(buf, 0, key, 0, length);
  66. return key;
  67. }
  68. /*
  69.  * Format style note
  70.  *  ---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----
  71.  *  Comment: *******
  72.  *  <base64-encoded body>
  73.  *  ---- END SSH2 ENCRYPTED PRIVATE KEY ----
  74.  * 
  75.  *  body = MAGIC_VAL || body-length || type(string) || encryption-algorithm-name(string) || encrypted-body(string)
  76.  *  encrypted-body = array of BigInteger(algorithm-specific)
  77.  */ 
  78. public static SSH2UserAuthKey FromSECSHStyleStream(Stream strm, string passphrase) {
  79. StreamReader r = new StreamReader(strm, Encoding.ASCII);
  80. string l = r.ReadLine();
  81. if(l==null || l!="---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----") throw new SSHException("Wrong key format");
  82. l = r.ReadLine();
  83. StringBuilder buf = new StringBuilder();
  84. while(l!="---- END SSH2 ENCRYPTED PRIVATE KEY ----") {
  85. if(l.IndexOf(':')==-1)
  86. buf.Append(l);
  87. else {
  88. while(l.EndsWith("\")) l = r.ReadLine();
  89. }
  90. l = r.ReadLine();
  91. if(l==null) throw new SSHException("Key is broken");
  92. }
  93. r.Close();
  94. byte[] keydata = Base64.Decode(Encoding.ASCII.GetBytes(buf.ToString()));
  95. //Debug.WriteLine(DebugUtil.DumpByteArray(keydata));
  96. /*
  97. FileStream fs = new FileStream("C:\IOPort\keydata1.bin", FileMode.Create);
  98. fs.Write(keydata, 0, keydata.Length);
  99. fs.Close();
  100. */
  101. SSH2DataReader re = new SSH2DataReader(keydata);
  102. int    magic         = re.ReadInt32();
  103. if(magic!=MAGIC_VAL) throw new SSHException("key file is broken");
  104. int    privateKeyLen = re.ReadInt32();
  105. string type          = Encoding.ASCII.GetString(re.ReadString());
  106. string ciphername    = Encoding.ASCII.GetString(re.ReadString());
  107. int    bufLen        = re.ReadInt32();
  108. if(ciphername!="none") {
  109. CipherAlgorithm algo = CipherFactory.SSH2NameToAlgorithm(ciphername);
  110. byte[] key = PassphraseToKey(passphrase, CipherFactory.GetKeySize(algo));
  111. Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, algo, key);
  112. byte[] tmp = new Byte[re.Image.Length-re.Offset];
  113. c.Decrypt(re.Image, re.Offset, re.Image.Length-re.Offset, tmp, 0);
  114. re = new SSH2DataReader(tmp);
  115. }
  116. int parmLen          = re.ReadInt32();
  117. if(parmLen<0 || parmLen>re.Rest)
  118. throw new SSHException(Strings.GetString("WrongPassphrase"));
  119. if(type.IndexOf("if-modn")!=-1) {
  120. //mindterm mistaken this order of BigIntegers
  121. BigInteger e = re.ReadBigIntWithBits();
  122. BigInteger d = re.ReadBigIntWithBits();
  123. BigInteger n = re.ReadBigIntWithBits();
  124. BigInteger u = re.ReadBigIntWithBits();
  125. BigInteger p = re.ReadBigIntWithBits();
  126. BigInteger q = re.ReadBigIntWithBits();
  127. return new SSH2UserAuthKey(new RSAKeyPair(e, d, n, u, p, q));
  128. }
  129. else if(type.IndexOf("dl-modp")!=-1) {
  130. if(re.ReadInt32()!=0) throw new SSHException("DSS Private Key File is broken");
  131. BigInteger p = re.ReadBigIntWithBits();
  132. BigInteger g = re.ReadBigIntWithBits();
  133. BigInteger q = re.ReadBigIntWithBits();
  134. BigInteger y = re.ReadBigIntWithBits();
  135. BigInteger x = re.ReadBigIntWithBits();
  136. return new SSH2UserAuthKey(new DSAKeyPair(p, g, q, y, x));
  137. }
  138. else
  139. throw new SSHException("unknown authentication method "+type);
  140. }
  141. public static SSH2UserAuthKey FromSECSHStyleFile(string filename, string passphrase) {
  142. return FromSECSHStyleStream(new FileStream(filename, FileMode.Open, FileAccess.Read), passphrase);
  143. }
  144. public void WritePrivatePartInSECSHStyleFile(Stream dest, string comment, string passphrase) {
  145. //step1 key body
  146. SSH2DataWriter wr = new SSH2DataWriter();
  147. wr.Write(0); //this field is filled later
  148. if(_keypair.Algorithm==PublicKeyAlgorithm.RSA) {
  149. RSAKeyPair rsa = (RSAKeyPair)_keypair;
  150. RSAPublicKey pub = (RSAPublicKey)_keypair.PublicKey;
  151. wr.WriteBigIntWithBits(pub.Exponent);
  152. wr.WriteBigIntWithBits(rsa.D);
  153. wr.WriteBigIntWithBits(pub.Modulus);
  154. wr.WriteBigIntWithBits(rsa.U);
  155. wr.WriteBigIntWithBits(rsa.P);
  156. wr.WriteBigIntWithBits(rsa.Q);
  157. }
  158. else {
  159. DSAKeyPair dsa = (DSAKeyPair)_keypair;
  160. DSAPublicKey pub = (DSAPublicKey)_keypair.PublicKey;
  161. wr.Write(0);
  162. wr.WriteBigIntWithBits(pub.P);
  163. wr.WriteBigIntWithBits(pub.G);
  164. wr.WriteBigIntWithBits(pub.Q);
  165. wr.WriteBigIntWithBits(pub.Y);
  166. wr.WriteBigIntWithBits(dsa.X);
  167. }
  168. int padding_len = 0;
  169. if(passphrase!=null) {
  170. padding_len = 8 - (int)wr.Length % 8;
  171. wr.Write(new byte[padding_len]);
  172. }
  173. byte[] encrypted_body = wr.ToByteArray();
  174. SSHUtil.WriteIntToByteArray(encrypted_body, 0, encrypted_body.Length - padding_len - 4);
  175. //encrypt if necessary
  176. if(passphrase!=null) {
  177. Cipher c = CipherFactory.CreateCipher(SSHProtocol.SSH2, CipherAlgorithm.TripleDES, PassphraseToKey(passphrase,24));
  178. Debug.Assert(encrypted_body.Length % 8 ==0);
  179. byte[] tmp = new Byte[encrypted_body.Length];
  180. c.Encrypt(encrypted_body, 0, encrypted_body.Length, tmp, 0);
  181. encrypted_body = tmp;
  182. }
  183. //step2 make binary key data
  184. wr = new SSH2DataWriter();
  185. wr.Write(MAGIC_VAL);
  186. wr.Write(0); //for total size
  187. wr.Write(_keypair.Algorithm==PublicKeyAlgorithm.RSA?
  188. "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}" :
  189. "dl-modp{sign{dsa-nist-sha1},dh{plain}}");
  190. wr.Write(passphrase==null? "none" : "3des-cbc");
  191. wr.WriteAsString(encrypted_body);
  192. byte[] rawdata = wr.ToByteArray();
  193. SSHUtil.WriteIntToByteArray(rawdata, 4, rawdata.Length); //fix total length
  194. //step3 write final data
  195. StreamWriter sw = new StreamWriter(dest, Encoding.ASCII);
  196. sw.WriteLine("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----");
  197. if(comment!=null)
  198. WriteKeyFileBlock(sw, "Comment: " + comment, true);
  199. WriteKeyFileBlock(sw, Encoding.ASCII.GetString(Base64.Encode(rawdata)), false);
  200. sw.WriteLine("---- END SSH2 ENCRYPTED PRIVATE KEY ----");
  201. sw.Close();
  202. }
  203. public void WritePublicPartInSECSHStyle(Stream dest, string comment) {
  204. StreamWriter sw = new StreamWriter(dest, Encoding.ASCII);
  205. sw.WriteLine("---- BEGIN SSH2 PUBLIC KEY ----");
  206. if(comment!=null)
  207. WriteKeyFileBlock(sw, "Comment: " + comment, true);
  208. WriteKeyFileBlock(sw, FormatBase64EncodedPublicKeyBody(), false);
  209. sw.WriteLine("---- END SSH2 PUBLIC KEY ----");
  210. sw.Close();
  211. }
  212. public void WritePublicPartInOpenSSHStyle(Stream dest) {
  213. StreamWriter sw = new StreamWriter(dest, Encoding.ASCII);
  214. sw.Write(SSH2Util.PublicKeyAlgorithmName(_keypair.Algorithm));
  215. sw.Write(' ');
  216. sw.WriteLine(FormatBase64EncodedPublicKeyBody());
  217. sw.Close();
  218. }
  219. private string FormatBase64EncodedPublicKeyBody() {
  220. SSH2DataWriter wr = new SSH2DataWriter();
  221. wr.Write(SSH2Util.PublicKeyAlgorithmName(_keypair.Algorithm));
  222. _keypair.PublicKey.WriteTo(wr);
  223. return Encoding.ASCII.GetString(Base64.Encode(wr.ToByteArray()));
  224. }
  225. private static void WriteKeyFileBlock(StreamWriter sw, string data, bool escape_needed) {
  226. char[] d = data.ToCharArray();
  227. int cursor = 0;
  228. const int maxlen = 70;
  229. while(cursor < d.Length) {
  230. if(maxlen >= d.Length-cursor)
  231. sw.WriteLine(d, cursor, d.Length-cursor);
  232. else {
  233. if(escape_needed) {
  234. sw.Write(d, cursor, maxlen-1);
  235. sw.WriteLine('\');
  236. cursor--;
  237. }
  238. else
  239. sw.WriteLine(d, cursor, maxlen);
  240. }
  241. cursor += maxlen;
  242. }
  243. }
  244. }
  245. }