Back to TWSSH

TWSSH Documentation

Complete API reference for TWSSH - a high-performance, enterprise-grade SSH library for .NET applications.

Installation

TWSSH targets multiple .NET versions for maximum compatibility:

NuGet Package

dotnet add package TwSsh

Manual Installation

Extract the SDK and add a reference to TwSsh.Core.dll in your project.

Quick Start

Here's a complete example to connect and run a command:

using TwSsh.Client;
using TwSsh.Authentication;
using TwSsh.Licensing;

// Initialize license (required)
LicenseManager.Instance.Initialize("YOUR-LICENSE-KEY");

// Create client with settings
var settings = new SshClientSettings
{
    Host = "example.com",
    Port = 22,
    Credential = new PasswordCredential("username", "password")
};

await using var client = new SshClient(settings);

// Connect and authenticate
await client.ConnectAsync();
await client.AuthenticateAsync(settings.Credential);

// Run a command
var result = await client.RunCommandAsync("uname -a");
Console.WriteLine(result.Output);
Console.WriteLine($"Exit code: {result.ExitCode}");
Tip

Use ConnectAndAuthenticateAsync() as a shorthand for both operations.

Licensing

TWSSH requires a valid license to operate. Initialize the license at application startup:

using TwSsh.Licensing;

// Option 1: Initialize with license key string
LicenseManager.Instance.Initialize("YOUR-LICENSE-KEY");

// Option 2: Load from file
LicenseManager.Instance.InitializeFromFile("path/to/license.lic");

// Option 3: Start a trial (30 days)
LicenseManager.Instance.InitializeTrial(30);

// Option 4: Auto-detect license from common locations
LicenseManager.Instance.TryAutoInitialize();

License Types

Type Connections Features
Trial 2 All Team features (30 days)
Developer 5 SSH, Shell, SFTP, SCP, Public Key Auth
Team 25 + Port Forwarding, Advanced Crypto, Connection Pooling
Enterprise Unlimited All features + Priority Support

SshClient

TwSsh.Client

The main class for SSH connections. Implements IAsyncDisposable.

Constructors

public SshClient(SshClientSettings settings)
public SshClient(string host, int port, SshCredential credential)

Properties

PropertyTypeDescription
State SshClientState Current connection state
IsConnected bool Whether connected to server
IsAuthenticated bool Whether authentication succeeded
ConnectionInfo SshConnectionInfo? Connection details after connect

Connection Methods

ValueTask ConnectAsync(CancellationToken ct = default)

Establishes connection and performs key exchange.

ValueTask ConnectAndAuthenticateAsync(CancellationToken ct = default)

Connects and authenticates using the credential from settings.

ValueTask<bool> AuthenticateAsync(SshCredential credential, CancellationToken ct = default)

Authenticates with the server. Returns true on success.

ValueTask DisconnectAsync(CancellationToken ct = default)

Gracefully disconnects from the server.

Command Execution

ValueTask<SshCommandResult> RunCommandAsync(string commandText, CancellationToken ct = default)

Executes a command and returns the result with output, error, and exit status.

ValueTask<SshCommand> CreateCommandAsync(string commandText, CancellationToken ct = default)

Creates a command for advanced scenarios with streaming output.

Shell Access

ValueTask<ShellStream> CreateShellAsync(PtyRequest? ptyRequest = null, CancellationToken ct = default)

Creates an interactive shell with optional pseudo-terminal.

Subsystems

ValueTask<ISessionChannel> OpenSubsystemChannelAsync(string subsystemName, CancellationToken ct = default)

Opens a subsystem channel (e.g., "sftp").

Port Forwarding

ValueTask<ForwardedPort> ForwardLocalPortAsync(string localHost, int localPort, string remoteHost, int remotePort, CancellationToken ct = default)

Forwards a local port to a remote destination through the SSH tunnel.

ValueTask<ForwardedPort> ForwardRemotePortAsync(string remoteHost, int remotePort, string localHost, int localPort, CancellationToken ct = default)

Requests the server forward a remote port to a local destination.

SshClientSettings

TwSsh.Client

Configuration for SSH connections.

PropertyTypeDefaultDescription
Host string "" Remote host address
Port int 22 Remote port
Credential SshCredential? null Authentication credential
ConnectionTimeout TimeSpan 30s Connection timeout
OperationTimeout TimeSpan 1m Operation timeout
KeepAliveInterval TimeSpan 0 Keep-alive interval (0 = disabled)
AutoReconnect bool false Auto-reconnect on connection loss
HostKeyVerification HostKeyVerificationMode AutoAdd Host key verification mode
HostKeyCallback Func<HostKeyEventArgs, bool>? null Custom host key verification

Algorithm Preferences

You can specify preferred algorithms (in order of preference):

Authentication

TwSsh.Authentication

PasswordCredential

Simple password authentication.

var credential = new PasswordCredential("username", "password");

PrivateKeyCredential

Public key authentication using private keys.

// Load from file (pass null for unencrypted keys)
var key = PrivateKeyParser.LoadFromFile("~/.ssh/id_rsa", null);
var credential = new PrivateKeyCredential("username", key);

// With passphrase
var key = PrivateKeyParser.LoadFromFile("~/.ssh/id_rsa", "passphrase");

// Multiple keys
var credential = new PrivateKeyCredential("username", key1, key2, key3);

KeyboardInteractiveCredential

For servers requiring keyboard-interactive authentication.

// Simple password-based keyboard-interactive
var credential = KeyboardInteractiveCredential.FromPassword("username", "password");

// Custom prompt handler
var credential = new KeyboardInteractiveCredential("username",
    (instruction, prompts, echos) => {
        // Return responses for each prompt
        return prompts.Select(p => GetResponse(p)).ToArray();
    });

Command Execution

Simple Command

var result = await client.RunCommandAsync("ls -la");

Console.WriteLine(result.Output);      // stdout
Console.WriteLine(result.ErrorOutput);       // stderr
Console.WriteLine(result.ExitCode);  // exit code
Console.WriteLine(result.IsSuccess);   // true if exit code == 0

Streaming Output

await using var cmd = await client.CreateCommandAsync("long-running-command");

// Read output as it arrives
var buffer = new byte[4096];
int bytesRead;
while ((bytesRead = await cmd.OutputStream.ReadAsync(buffer)) > 0)
{
    Console.Write(Encoding.UTF8.GetString(buffer, 0, bytesRead));
}

SshCommandResult Properties

PropertyTypeDescription
OutputstringStandard output
ErrorOutputstringStandard error
ExitCodeintExit code
IsSuccessboolTrue if exit code is 0

Interactive Shell

ShellStream provides an interactive shell session with PTY support.

Basic Shell

await using var shell = await client.CreateShellAsync();

// Send commands
await shell.WriteLineAsync("cd /var/log");
await shell.WriteLineAsync("ls -la");

// Read response
var output = await shell.ReadLineAsync();

With PTY Settings

var pty = new PtyRequest
{
    TerminalType = "xterm-256color",
    WidthChars = 120,
    HeightRows = 40,
    Modes = new Dictionary<TerminalMode, uint>
    {
        [TerminalMode.Echo] = 1
    }
};

await using var shell = await client.CreateShellAsync(pty);

Pattern Matching

// Wait for specific text
var output = await shell.ExpectAsync("$ ", TimeSpan.FromSeconds(5));

// Wait for regex pattern
var output = await shell.ExpectAsync(new Regex(@"password:\s*$"), TimeSpan.FromSeconds(10));

Window Resize

await shell.SendWindowChangeAsync(132, 50);

SFTP

TWSSH provides a full-featured SFTP client for secure file transfer operations:

using TwSsh.Sftp;

// Create SFTP client from authenticated connection
await using var sftp = await SftpClient.ConnectAsync(client);

// Upload a file
await sftp.UploadFileAsync("local.txt", "/remote/path/file.txt");

// Download a file
await sftp.DownloadFileAsync("/remote/data.csv", "local.csv");

// List directory contents
var files = await sftp.ListDirectoryAsync("/home/user");
foreach (var file in files)
{
    Console.WriteLine($"{file.FileName} - {file.Attributes.Size} bytes");
}

Progress Reporting

var progress = new Progress<SftpTransferProgress>(p =>
{
    Console.WriteLine($"File: {p.FileName}");
    Console.WriteLine($"Progress: {p.BytesTransferred} / {p.TotalBytes} bytes");
    Console.WriteLine($"Percent: {p.PercentComplete:F1}%");
    Console.WriteLine($"Speed: {p.BytesPerSecond / 1024.0:F1} KB/s");
    Console.WriteLine($"Elapsed: {p.Elapsed}");
    Console.WriteLine($"ETA: {p.EstimatedRemaining}");
});

await sftp.UploadFileAsync("large.zip", "/backup/large.zip",
    new SftpTransferOptions(), progress);

SftpTransferProgress Properties

PropertyTypeDescription
FileNamestringName of file being transferred
BytesTransferredlongBytes transferred so far
TotalByteslongTotal file size in bytes
PercentCompletedoublePercentage complete (0-100)
BytesPerSeconddoubleCurrent transfer speed
ElapsedTimeSpanTime elapsed since start
EstimatedRemainingTimeSpanEstimated time remaining
IsCompleteboolWhether transfer is finished

Directory Operations

// Create directory
await sftp.CreateDirectoryAsync("/home/user/newdir");

// Delete file
await sftp.DeleteFileAsync("/tmp/oldfile.txt");

// Rename/move
await sftp.RenameAsync("/old/path.txt", "/new/path.txt");

// Check existence
if (await sftp.ExistsAsync("/path/to/file"))
    Console.WriteLine("File exists!");

Stream-Based Access

// Open remote file as a stream
await using var stream = await sftp.OpenFileAsync(
    "/remote/file.txt", FileMode.Open, FileAccess.Read);

using var reader = new StreamReader(stream);
var content = await reader.ReadToEndAsync();
Full SFTP Support

SftpClient supports SFTP protocol versions 3-6, automatic version negotiation, resume transfers, batch operations, symbolic links, and server extension detection.

Port Forwarding

Local Port Forwarding

Forward a local port to a remote destination:

// Forward local port 8080 to remote server's port 80
await using var forward = await client.ForwardLocalPortAsync(
    "127.0.0.1",  // local host
    8080,         // local port
    "localhost",  // remote host (relative to SSH server)
    80            // remote port
);

// Now http://127.0.0.1:8080 connects to remote:80
Console.WriteLine("Port forwarding active...");
await Task.Delay(TimeSpan.FromMinutes(10));

Remote Port Forwarding

Request the server forward a remote port to your local machine:

// Forward remote port 9000 to local port 3000
await using var forward = await client.ForwardRemotePortAsync(
    "0.0.0.0",    // remote bind address
    9000,         // remote port
    "127.0.0.1",  // local host
    3000          // local port
);

// Connections to server:9000 now reach local:3000

Accessing Port Information

The forwarding methods return the base ForwardedPort type. To access port-specific properties, cast to the concrete type:

// ForwardLocalPortAsync returns LocalPortForwarder
await using var tunnel = await client.ForwardLocalPortAsync(
    "127.0.0.1", 0,  // port 0 = auto-assign
    "localhost", 3306
);

// Cast to access the actual assigned port
if (tunnel is LocalPortForwarder lpf)
{
    Console.WriteLine($"Tunnel listening on port {lpf.LocalPort}");
}

// ForwardRemotePortAsync returns RemotePortForwarder
await using var remote = await client.ForwardRemotePortAsync(
    "0.0.0.0", 0,
    "127.0.0.1", 8080
);

if (remote is RemotePortForwarder rpf)
{
    Console.WriteLine($"Remote port {rpf.RemotePort} forwarded");
}

ForwardedPort Properties

TypePropertyDescription
LocalPortForwarderLocalHostLocal bind address
LocalPortForwarderLocalPortLocal port number (useful with port 0)
LocalPortForwarderRemoteHostRemote destination host
LocalPortForwarderRemotePortRemote destination port
RemotePortForwarderRemoteHostRemote bind address
RemotePortForwarderRemotePortRemote port number
RemotePortForwarderLocalHostLocal destination host
RemotePortForwarderLocalPortLocal destination port
BothErrorOccurredEvent for forwarding errors

Private Keys

TwSsh.Core.Authentication PrivateKeyParser

TwSsh.Authentication PrivateKeyCredential

Important: Different Namespaces

PrivateKeyParser is in TwSsh.Core.Authentication, while PrivateKeyCredential is in TwSsh.Authentication. Make sure to include both using statements.

Loading Keys

using TwSsh.Core.Authentication;  // For PrivateKeyParser
using TwSsh.Authentication;        // For PrivateKeyCredential

// From file (pass null for unencrypted keys)
var key = PrivateKeyParser.LoadFromFile("/path/to/key", null);

// From file with passphrase
var key = PrivateKeyParser.LoadFromFile("/path/to/key", "passphrase");

// From string (pass null for unencrypted keys)
var key = PrivateKeyParser.Parse(keyContent, null);

// From binary data
var key = PrivateKeyParser.ParseBinary(keyBytes);

Supported Formats

FormatHeader
OpenSSHBEGIN OPENSSH PRIVATE KEY
PEM RSABEGIN RSA PRIVATE KEY
PEM ECBEGIN EC PRIVATE KEY
PKCS#8BEGIN PRIVATE KEY
PKCS#8 EncryptedBEGIN ENCRYPTED PRIVATE KEY

Supported Key Types

Channels

TwSsh.Connection

ISessionChannel

Session channels support commands, shells, and subsystems.

MethodDescription
RequestPtyAsync()Request pseudo-terminal
RequestShellAsync()Start interactive shell
RequestExecAsync()Execute command
RequestSubsystemAsync()Start subsystem
SetEnvironmentVariableAsync()Set environment variable
SendSignalAsync()Send signal to process

Events

SshClient Events

EventEventArgsDescription
Disconnected SshDisconnectEventArgs Connection was closed
HostKeyReceived HostKeyEventArgs Server's host key received

Host Key Verification

client.HostKeyReceived += (sender, e) => {
    Console.WriteLine($"Host key: {e.Fingerprint}");
    Console.WriteLine($"Algorithm: {e.HostKeyAlgorithm}");

    // Set e.Accept = false to reject the connection
    e.Accept = VerifyFingerprint(e.Fingerprint);
};

Exceptions

TwSsh.Common

ExceptionDescription
SshException Base exception for all SSH errors
SshConnectionException Connection-related errors (includes DisconnectReason)
SshAuthenticationException Authentication failures (includes AllowedMethods)
SshChannelException Channel operations failed
LicenseException License validation errors
try
{
    await client.ConnectAndAuthenticateAsync();
}
catch (SshAuthenticationException ex)
{
    Console.WriteLine($"Auth failed. Allowed methods: {string.Join(", ", ex.AllowedMethods)}");
}
catch (SshConnectionException ex)
{
    Console.WriteLine($"Connection failed: {ex.DisconnectReason}");
}
catch (LicenseException ex) when (ex.ErrorType == LicenseErrorType.Expired)
{
    Console.WriteLine("License has expired");
}

Logging

TwSsh.Common

Implement ISshLogger for custom logging:

public class ConsoleLogger : ISshLogger
{
    public void Log(SshLogLevel level, string message, Exception? ex = null)
    {
        Console.WriteLine($"[{level}] {message}");
        if (ex != null) Console.WriteLine($"  Exception: {ex.Message}");
    }

    public bool IsEnabled(SshLogLevel level) => level >= SshLogLevel.Info;
}

// Use in settings
var settings = new SshClientSettings
{
    Host = "example.com",
    Credential = credential,
    Logger = new ConsoleLogger()
};

SshLogLevel

TraceDetailed protocol messages
DebugDebugging information
InfoGeneral information
WarningWarning messages
ErrorError messages
FatalFatal errors

Enumerations

SshClientState

DisconnectedNot connected
ConnectingConnection in progress
ConnectedConnected, not authenticated
AuthenticatedReady for use
DisconnectingDisconnection in progress

HostKeyVerificationMode

NoneNo verification (insecure)
AutoAddAuto-accept unknown keys
StrictReject unknown keys
CallbackUse custom callback

LicenseType

NoneNo valid license
Trial30-day trial
DeveloperDeveloper license
TeamTeam license
EnterpriseEnterprise license

SshDisconnectReason

HostNotAllowedToConnect1
ProtocolError2
KeyExchangeFailed3
MacError5
CompressionError6
ServiceNotAvailable7
ProtocolVersionNotSupported8
HostKeyNotVerifiable9
ConnectionLost10
ByApplication11
TooManyConnections12
AuthCancelledByUser13
NoMoreAuthMethodsAvailable14

Supported Algorithms

Key Exchange

Host Key

Encryption

MAC

Note

AEAD ciphers (ChaCha20-Poly1305, AES-GCM) don't require separate MAC algorithms as they provide built-in authentication.

Troubleshooting

Common issues and solutions when using TWSSH.

Connection Errors

Error MessageCauseSolution
Connection timed out Server unreachable or firewall blocking Verify host/port, check firewall rules, increase ConnectionTimeout
Connection refused SSH server not running on target port Verify SSH service is running, check port number
Host key verification failed Server key changed or not trusted Use HostKeyVerificationMode.Callback to verify key fingerprint
No matching key exchange Server doesn't support modern algorithms Configure KeyExchangeAlgorithms in settings to include legacy algorithms

Authentication Errors

Error MessageCauseSolution
Authentication failed Invalid credentials Verify username/password, check AllowedMethods in exception
Permission denied (publickey) Key not authorized on server Add public key to server's ~/.ssh/authorized_keys
Invalid key format Unsupported or corrupt private key Use OpenSSH format, verify key file integrity
Passphrase required Encrypted key without passphrase Provide passphrase to PrivateKeyParser.LoadFromFile()

License Errors

Error MessageCauseSolution
License not initialized No license loaded before SSH operations Call LicenseManager.Instance.Initialize() at app startup
License expired License validity period ended Renew license at [email protected]
Feature not available Feature requires higher license tier Upgrade license or use LicenseManager.Instance.HasFeature() to check
Connection limit exceeded Too many concurrent connections for license Close unused connections or upgrade license tier

SFTP Errors

Error MessageCauseSolution
No such file Remote path doesn't exist Verify path, use ExistsAsync() to check first
Permission denied Insufficient permissions on remote Check file/directory permissions on server
Directory not empty Attempting to delete non-empty directory Use recursive delete or empty directory first

Debugging Tips

// Check license status
var info = LicenseManager.Instance.LicenseInfo;
Console.WriteLine($"License: {info.Type}, Expires: {info.Expires}");
Console.WriteLine($"Max connections: {info.MaxConnections}");

// Check connection info after connect
await client.ConnectAsync();
Console.WriteLine($"Server: {client.ConnectionInfo.ServerVersion}");
Console.WriteLine($"Algorithms: {client.ConnectionInfo.Algorithms}");

// Handle auth failure to see allowed methods
try
{
    await client.AuthenticateAsync(credential);
}
catch (SshAuthenticationException ex)
{
    Console.WriteLine($"Allowed methods: {string.Join(", ", ex.AllowedMethods)}");
}

© 2025 TWSSH. All rights reserved.

[email protected]