Secure File Transfer in C# Using SFTP with Private Key Authentication

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) { }
    }
}

Tags: C# SFTP file transfer private key authentication SharpSsh

Posted on Fri, 08 May 2026 05:45:47 +0000 by djlfreak