65.9K
CodeProject 正在变化。 阅读更多。
Home

sharpSsh - .NET 的安全 Shell (SSH) 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.91/5 (118投票s)

2005年10月16日

BSD

5分钟阅读

viewsIcon

10709493

downloadIcon

87842

SSH2 协议的 C# 实现。

引言

最近,我需要从我的 C# 代码连接到 SSH 服务器。我需要执行一个简单的任务:登录到远程 Linux 设备,执行一个命令并读取响应。我知道有很多免费的 Java SSH 库,我希望能找到一个免费的 .NET 库来完成这个任务,但我只找到了商业组件。在试验了一个名为 JSch 的开源 Java SSH 库之后,我决定尝试将其移植到 C#,仅作为一种练习。结果就是附带的 sharpSsh 库和这篇解释如何使用它的文章。

背景

SSH (Secure Shell) 是一种通过网络登录到另一台计算机、在远程机器上执行命令以及在机器之间移动文件的协议。它在不安全的通道上提供强大的身份验证和安全通信。JSch 库是 SSH2 协议套件的纯 Java 实现;它包含许多功能,如端口转发、X11 转发、安全文件传输,并支持多种加密和 MAC 算法。JSch 根据 BSD 风格的许可证授权。

我的 C# 版本不是 JSch 的完整移植。我只移植了完成我的简单任务所需的最低限度的功能。以下列表总结了该库支持的功能

  • 密钥交换:diffie-hellman-group-exchange-sha1, diffie-hellman-group1-sha1。
  • 加密:3des-cbc
  • MAC:hmac-md5
  • 主机密钥类型:ssh-rsa 和部分 ssh-dss。
  • 用户认证:password, publickey (RSA)
  • 生成 RSA 密钥对。
  • 更改私钥的密码。
  • SCP 和 SFTP

请查看我的 主页 以获取 SharpSSH 的最新版本和功能列表。

使用代码

首先声明一下。代码未经完全测试,我不能保证任何级别的性能、安全性或质量。该库和文章的目的是让我自己(也许还有您)了解 SSH 协议以及 C# 和 Java 之间的差异。

为了提供最简单的 SSH 通信 API,我在 Tamir.SharpSsh 命名空间下创建了两个包装类,它们封装了 JSch 的内部结构

  • SshStream - 一个基于流的类,用于在 SSH 通道上读写数据。
  • Scp - 一个用于处理 SSH 通道上文件传输的类。

在 SSH 通道上读写数据

SshStream 类使在 SSH 通道上读写数据如同任何 I/O 读写任务一样简单。它的构造函数接收三个参数:远程主机名或 IP 地址、用户名和密码。它在构造时立即连接到远程服务器。

//Create a new SSH stream
SshStream ssh = new SshStream("remoteHost", "username", "password");

//..The SshStream has successfully established the connection.

现在,我们可以设置一些属性

//Set the end of response matcher character
ssh.Prompt = "#";
//Remove terminal emulation characters
ssh.RemoveTerminalEmulationCharacters = true;

Prompt 属性是一个匹配响应结尾的字符串。当使用 ReadResponse() 方法时,设置此属性非常有用。该方法会一直读取并缓冲来自 SSH 通道的数据,直到在响应中匹配到 Prompt 字符串,然后才会返回结果字符串。例如,Linux shell 提示符通常以 '#' 或 '$' 结尾,所以在执行命令后,匹配这些字符以检测命令响应的结束会很有用(该属性实际上接收任何正则表达式模式并将其与响应进行匹配,因此可以匹配更复杂的模式,例如 "\[[^@]*@[^]]*]#\s" ,它匹配 Linux 主机的 bash shell 提示符 [user@host dir]#)。Prompt 属性的默认值是 "\n",它只是告诉 ReadResponse() 方法返回一行响应。

响应字符串通常包含转义序列字符,这些字符是终端仿真信号,用于指示连接的 SSH 客户端如何显示响应。但是,如果我们只对“干净”的响应内容感兴趣,可以通过将 RemoveTerminalEmulationCharacters 属性设置为 true 来省略这些字符。

现在,向 SSH 流读写数据将按如下方式进行

//Writing to the SSH channel
ssh.Write( command );

//Reading from the SSH channel
string response = ssh.ReadResponse();

当然,仍然可以使用 SshStream 的标准 Read/Write I/O 方法,这些方法在 System.IO.Stream API 中可用。

使用 SCP 传输文件

使用 Scp 类与 SSH 服务器之间传输文件非常简单。以下代码片段演示了如何做到这一点

//Create a new SCP instance
Scp scp = new Scp();

//Copy a file from local machine to remote SSH server
scp.To("C:\fileName", "remoteHost", 
             "/pub/fileName", "username", "password");

//Copy a file from remote SSH server to local machine
scp.From("remoteHost", "/pub/fileName", 
               "username", "password", "C:\fileName");

Scp 类还具有一些用于跟踪文件传输进度的事件

  • Scp.OnConnecting - 在 SSH 连接初始化时触发。
  • Scp.OnStart - 在文件传输开始时触发。
  • Scp.OnEnd - 在文件传输结束时触发。
  • Scp.OnProgress - 在文件传输进度更新时触发(可以设置 ProgressUpdateInterval 属性来修改毫秒级的进度更新间隔时间)。

运行示例

演示项目是一个简单的控制台应用程序,演示了 SshStreamScp 类的用法。它会提示用户输入远程 SSH 服务器的主机名、用户名和密码,并展示了一个简单的 SSH 会话以及与远程 SSH 机器之间进行文件传输的示例。

以下是连接到 Linux shell 的 SSH 连接的屏幕截图

这是使用 SCP 将文件从 Linux 机器传输到我的 PC 的文件传输截图

在演示项目 zip 文件中,您还将找到一个 examples 目录,其中包含一些展示原始 JSch API 用法的类。这些示例直接从原始 JSch 库随附的 Java 示例翻译而来,并展示了公钥认证、已知主机文件、密钥生成、SFTP 等高级选项的用法。

参考文献

  • SharpSSH 主页 - 新版本和 bug 修复将发布在此处,请查看此页面以获取最新更新。
  • JSch - JSch 是 SSH2 协议套件的纯 Java 实现。我的 C# 库基于此项目。
  • Mentalis.org - Mentalis.org 包含一些很棒的 .NET 安全和网络项目。我将他们的 HMAC 和 Diffie Hellman 类用作我 SSH 实现的一部分。
  • Granados - 一个全功能的开源 C# SSH1 和 SSH2 实现。我是在完成自己的库之后发现这个项目的。

历史

  • 2005-10-16
    • 初始版本。
  • 2005-10-22
    • 修复了 Scp 类中的两个 bug
  • 2005-10-29
    • 添加了在密钥交换阶段使用 DSA 签名 ('ssh-dss') 对服务器进行身份验证的选项。
  • 2005-10-29
    • 所有未来的更新将发布在我的 主页 上。
© . All rights reserved.