SFTP provides encrypted file transfer over SSH, eliminating the need for a separate FTP server. It uses existing SSH infrastructure, reducing resource usage and improving security compared to traditinoal FTP.
Key Characteristics of SFTP vs FTP
- FTP: Unencrypted protocol requiring a dedicated server installation. Suitable for simple data sharing.
- SFTP: Encrypts both authentication and data transmission. Runs over SSH; typically enabled when SSH access is configured. May have slightly lower throughput due to encryption overhead, though often negligible in practice.
Public/Private Key Authentication Setup
When password-based login is disallowed, SFTP can authenticate using an RSA/DSA/SSH key pair. Supported keys start with BEGI followed by two skipped bytes and then algorithm identifiers like DSA, RSA, or SSH.
The following example demonstrates C# file operations over SFTP using a private key with the SharpSsh library (JSch backend).
Establishing Connection
string status;
SshTransferHandler client = SshTransferHandler.Build("/download/", out status);
client.EstablishLink();
Uploading Files with Directory Preparation
if (!client.PathExists("/telSale/"))
client.MakePath("/telSale/");
string dateFolder = "/telSale/" + DateTime.Now.ToString("yyyyMMdd") + "/";
if (!client.PathExists(dateFolder))
client.MakePath(dateFolder);
string targetSubfolder = dateFolder + "insPolicy/";
if (!client.PathExists(targetSubfolder))
client.MakePath(targetSubfolder);
client.SendFile(@"D:\sftp_put\insPolicy.txt");
client.TearDown();
Downloading Files
string downloadRoot = "/upload/telSale/" + DateTime.Now.ToString("yyyyMMdd") + "/insPolicy/";
SshTransferHandler receiver = SshTransferHandler.Build(downloadRoot, out status);
receiver.EstablishLink();
receiver.FetchFile("insPolicy.txt", @"D:\sftp_put\upload");
receiver.TearDown();
Connection Factory Method
public static SshTransferHandler Build(string remoteBase, out string err)
{
err = string.Empty;
try
{
string host = "211.101.11.33";
string user = "trade_name";
string secret = null; // No password for key auth
return new SshTransferHandler(host, user, secret, remoteBase);
}
catch (Exception ex)
{
err = ex.Message;
return null;
}
}
SFTP Handler Implementation
using System;
using Tamir.SharpSsh.jsch;
public class SshTransferHandler
{
private Session _sshSession;
private ChannelSftp _sftpChannel;
private string _baseDir = "/";
private const string DefaultBase = "/download/";
public SshTransferHandler(string address, string account, string pwd, string rootPath)
{
string[] parts = address.Split(':');
string machine = parts[0];
int port = parts.Length > 1 ? int.Parse(parts[1]) : 22;
JSch engine = new JSch();
engine.AddIdentity(@"D:\MTS-SFTP\Privite-Key\Identity");
_sshSession = engine.GetSession(account, machine, port);
_sshSession.SetConfig("StrictHostKeyChecking", "no");
CustomPrompt credProvider = new CustomPrompt();
credProvider.SetSecret(pwd);
_sshSession.SetUserInfo(credProvider);
if (!string.IsNullOrEmpty(rootPath))
_baseDir = rootPath;
}
public bool IsLinked => _sshSession.IsConnected;
public void EstablishLink()
{
if (!IsLinked)
{
_sshSession.Connect();
var channel = _sshSession.OpenChannel("sftp");
channel.Connect();
_sftpChannel = (ChannelSftp)channel;
}
}
public void TearDown()
{
if (IsLinked)
{
_sftpChannel.Disconnect();
_sshSession.Disconnect();
}
}
public void SendFile(string fullLocalPath)
{
string destination = "/download/telSale/" + DateTime.Now.ToString("yyyyMMdd") + "/insPolicy/";
_sftpChannel.Put(fullLocalPath, destination);
}
public void FetchFile(string remoteFile, string localDestination)
{
string remoteFullPath = _baseDir + remoteFile;
_sftpChannel.Get(remoteFullPath, localDestination);
}
public bool PathExists(string directory)
{
try
{
_sftpChannel.Ls(DefaultBase + directory.Trim());
return true;
}
catch (SftpException)
{
return false;
}
}
public void MakePath(string directory)
{
if (!PathExists(directory))
{
_sftpChannel.Mkdir(DefaultBase + directory.Trim('/'));
}
}
private class CustomPrompt : IUserInfo
{
private string _secret;
public void SetSecret(string value) => _secret = value;
public string GetPassword() => _secret;
public string GetPassphrase() => null;
public bool PromptPassword(string message) => true;
public bool PromptPassphrase(string message) => true;
public bool PromptYesNo(string message) => true;
public void ShowMessage(string message) { }
}
}