/// <summary> /// Fill this store with elements from an openssh known_hosts file /// </summary> /// <param name="filePath">The path of the file to read</param> public void ImportKnownHostsFromFile(string filePath) { using (var fStream = File.OpenText(filePath)) { while (!fStream.EndOfStream) { KnownHost createdHost; if (KnownHost.TryParse(fStream.ReadLine(), out createdHost)) { _knownHosts.Add(createdHost); } } } }
/// <summary> /// Attempts to parse a line from an openssh known_hosts file /// </summary> /// <param name="hostLine"></param> /// <param name="host"></param> /// <returns><c>true</c> if the host line could be parsed. <c>false</c> if an error occurred</returns> public static bool TryParse(string hostLine, out KnownHost host) { try { return(UnsafeTryParse(hostLine, out host)); } catch (FormatException) { host = null; return(false); } catch (ArgumentException) { host = null; return(false); } }
/// <summary> /// Add a host to this store. /// </summary> /// <param name="hostname">The name of the host to add</param> /// <param name="portNumber"></param> /// <param name="keyType">The algorithm of the public key</param> /// <param name="pubKey">The public key of the host to add</param> /// <param name="storeHostnameHashed">Whether the hostname should be stored as a SHA1 hash</param> /// <param name="marker">An optional <c>@</c> prefixed string that corresponds to a marker for this host. See the <c>man 8 sshd</c> section about known_hosts for valid markers</param> /// <exception cref="FormatException">Thrown if the given arguments cannor be parsed into a valid host entry</exception> public void AddHost(string hostname, UInt16 portNumber, string keyType, byte[] pubKey, bool storeHostnameHashed, string marker = "") { string hostNameWithPort = string.Format("[{0}:{1}]", hostname, portNumber); string hostnameSection; if (!string.IsNullOrEmpty(marker)) { if (!marker.StartsWith("@")) { throw new FormatException("The given host marker must be prefixed with \'@\'. See the \'man 8 sshd\' section about known_hosts for more details on markers"); } marker = string.Format("{0} ", marker); } if (storeHostnameHashed) { byte[] salt = new byte[20]; Sftp.GeneXusSftpUtils.CryptoAbstractionSftp.GenerateRandom(salt); HMACSHA1 hmac = new HMACSHA1(salt); byte[] hash = hmac.ComputeHash(Encoding.ASCII.GetBytes(hostNameWithPort)); hostnameSection = string.Format("|1|{0}|{1}", Convert.ToBase64String(salt), Convert.ToBase64String(hash)); } else { hostnameSection = hostNameWithPort; } string hostToParse = string.Format("{3}{0} {1} {2}", hostnameSection, keyType, Convert.ToBase64String(pubKey), marker); KnownHost newHost; if (!KnownHost.TryParse(hostToParse, out newHost)) { throw new FormatException("Malformed input: Failed to create entry. If you specified a marker, ensure it is valid (see the \'man 8 sshd\' section on known_hosts for more details on markers)"); } _knownHosts.Add(newHost); }
private static bool UnsafeTryParse(string hostLine, out KnownHost host) { host = null; if (string.IsNullOrEmpty(hostLine) || hostLine.StartsWith("#")) { return(false); } bool hasSpecialPrefix = hostLine.StartsWith("@"); string[] sectionedLine = hostLine.Split(' '); if (hasSpecialPrefix && sectionedLine.Length < 4) { return(false); } else if (sectionedLine.Length < 3) { return(false); } HostPubkeyMarker marker = hasSpecialPrefix ? ParseSpecialOperand(sectionedLine[0]) : HostPubkeyMarker.None; if (marker == HostPubkeyMarker.Error) { return(false); } int sectionOffset = hasSpecialPrefix ? 1 : 0; string hostNameSecion = sectionedLine[sectionOffset]; string keyTypeSection = sectionedLine[1 + sectionOffset]; string pubKeySection = sectionedLine[2 + sectionOffset]; host = new KnownHost(hostNameSecion, keyTypeSection, pubKeySection, marker); return(true); }