{"id":30321134,"url":"https://github.com/aimeast/fxssh","last_synced_at":"2025-08-17T21:20:11.154Z","repository":{"id":32159073,"uuid":"35732204","full_name":"Aimeast/FxSsh","owner":"Aimeast","description":"FxSsh is a lightweight SSH server side library.","archived":false,"fork":false,"pushed_at":"2025-03-18T14:43:17.000Z","size":212,"stargazers_count":152,"open_issues_count":7,"forks_count":59,"subscribers_count":13,"default_branch":"dev","last_synced_at":"2025-08-01T01:59:46.687Z","etag":null,"topics":["aes","csharp","dotnet","dotnet-core","ecdh","ecdsa","net8","rsa","ssh","ssh-reinforcement","ssh-server"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Aimeast.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-05-16T16:59:20.000Z","updated_at":"2025-06-15T01:54:56.000Z","dependencies_parsed_at":"2025-02-07T10:37:38.257Z","dependency_job_id":null,"html_url":"https://github.com/Aimeast/FxSsh","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/Aimeast/FxSsh","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aimeast%2FFxSsh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aimeast%2FFxSsh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aimeast%2FFxSsh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aimeast%2FFxSsh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Aimeast","download_url":"https://codeload.github.com/Aimeast/FxSsh/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Aimeast%2FFxSsh/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270908094,"owners_count":24666111,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aes","csharp","dotnet","dotnet-core","ecdh","ecdsa","net8","rsa","ssh","ssh-reinforcement","ssh-server"],"created_at":"2025-08-17T21:20:06.890Z","updated_at":"2025-08-17T21:20:11.128Z","avatar_url":"https://github.com/Aimeast.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"## FxSsh\nFxSsh is a lightweight [SSH](https://en.wikipedia.org/wiki/Secure_Shell) server side library.\n\n---\n### Nuget\n[![NuGet version](https://badge.fury.io/nu/FxSsh.svg)](https://www.nuget.org/packages/FxSsh/)\n\n`PM\u003e Install-Package FxSsh`\n\nTarget `net8.0`\n\n### RFCs\nFxSsh adheres to the following RFC documents\n- [RFC4250](https://tools.ietf.org/html/rfc4250)  Protocol Assigned Numbers\n- [RFC4251](https://tools.ietf.org/html/rfc4251)  Protocol Architecture\n- [RFC4252](https://tools.ietf.org/html/rfc4252)  Authentication Protocol\n- [RFC4253](https://tools.ietf.org/html/rfc4253)  Transport Layer Protocol\n- [RFC4254](https://tools.ietf.org/html/rfc4254)  Connection Protocol\n- [RFC4344](https://tools.ietf.org/html/rfc4344)  Transport Layer Encryption Modes\n- [RFC5656](https://tools.ietf.org/html/rfc5656)  Elliptic Curve Algorithm Integration\n- [RFC6668](https://tools.ietf.org/html/rfc6668)  SHA-2 Data Integrity Algorithms\n- [RFC8332](https://tools.ietf.org/html/rfc8332)  Use of RSA Keys with SHA-2\n- [draft-ietf-secsh-filexfer-02](https://tools.ietf.org/html/draft-ietf-secsh-filexfer-02)  SSH File Transfer Protocol (sftp version 3)\n\n### Supported Algorithms\n\n| **Category**          | **Algorithms**                                                                |\n|-----------------------|-------------------------------------------------------------------------------|\n| **Public Key**        | RSA family: `rsa-sha2-256`, `rsa-sha2-512`\u003cbr\u003eECDsa family: `ecdsa-sha2-nistp256`, `ecdsa-sha2-nistp384`, `ecdsa-sha2-nistp521` |\n| **Key Exchange (KEX)**| DH family: `diffie-hellman-group14-sha256`, `diffie-hellman-group16-sha512`, `diffie-hellman-group18-sha512`\u003cbr\u003eECDH family: `ecdh-sha2-nistp256`, `ecdh-sha2-nistp384`, `ecdh-sha2-nistp521` |\n| **Encryption**        | `aes128-ctr`, `aes192-ctr`, `aes256-ctr`                                      |\n| **MAC**               | `hmac-sha2-256`, `hmac-sha2-512`                                              |\n\n### Supported Services\n\n| **Service**        | **Details**                                                             |\n|--------------------|-------------------------------------------------------------------------|\n| **Authentication** | `publickey`, `password`                                                 |\n| **Connection**     | `session` (e.g., exec, shell)\u003cbr\u003e`direct-tcpip`, `forwarded-tcpip`      |\n| **subsystem**      | `sftp (version 3)`                                                      |\n\n### Tested Clients\n\n| **Client**      | **Version**                                     |\n|-----------------|-------------------------------------------------|\n| OpenSSH         | `OpenSSH_for_Windows_9.5p1, LibreSSL 3.8.2`     |\n| PuTTY           | `Release 0.82`                                  |\n| WinSCP          | `6.3.6` (sftp only)                             |\n\n### Sample code\n```cs\nstatic int windowWidth, windowHeight;\n\nstatic void Main(string[] args)\n{\n    var rsa2048BitPem = @\"-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQClBPKsmiTxCoez\nE4Wt4nvNDVjLtkGQPUS/SbhJCL8J7pKrvsKRyXKM9GjGdxA7GKZR7sjqCWCU12oD\n+EJuf/mpcA0JsBY4gUU8bp95U5mEM+ZOr2aNXYXAXy/J6GQRyd1jgkD2pm1qsWZJ\nahvXNJGMgx1lqI9woKU+PRssMtv1YupAxsSlo+xcfvC57fkaKIwUeCr6CkUlpIJN\nzP5lvatKcpmjiWLSRHUpypx2wgZPz4SnB2qE77UH/yu1DlcsQgbVa7nr+qMWfxP7\nCpa+eTJC19c1GP+XxFaeqXDtuGaRlfBX/iihEcBnQuvsZJLg5jN0WKqvnpDfHgh/\nM4IopC2pAgMBAAECggEBAImt6ibV6NJvHa7sL9FXMEFxzE8SffsxEyWiBS5yLKnF\nsfu3CbEG6RrvZGeJuTIFK+caGekh78HfRGWRgSOehJe4lDgsAS4dtL1p8oYQmPnz\nL0khEKgLimdpQ37q9GrfCGZYq4jebFXjMts3u4i/JFyenC1QCHVIovWdmAk1Wc2N\n5bY+qlQZ4dSBl15cqNg0w4bbEF+yT+fOMm/raZANTr/IDIt88LcKpyimvUSGlZEE\nOWx4hXAPbF4h/tqeH4O+Xzmtq/1pWwdbwNqWwOXow320c97U4ofCuDXcy0TeOwiX\ngcPnaG99jX4Cy+IwdcVnDsJpN4FC2/sm1kGeOTRpIl0CgYEAy8gPV5RESpOyQ00j\ndr36JQoymLwXDS114tuMPF7dX5YX3S+yyhl0ADa11tVH15CzOaVSF1wfxDeb1TRs\nXcJoZBsxlH24BMPETB1ADy43pslRrkex54hcM4jDe3OYBTsVmV5A2sdxFGEKAbPn\nuWsk8jeZ9AsEV3M2vinzJmS5XVsCgYEAz04dSW0GXiTBESYmno9DJiyx3dT4T0eq\nbwtpZPCShEjU4BChwFg9V5fAmzw1iCrdYD68mwcxQYurp3Vgqo6u1YogRpeNfljq\nVpKnVDbd3a1CTYYyWw81f4HzflpmWLgq1BGKkdwD83xZaFh7Y46cm+xEtrJpiVFM\nGTagAokFvEsCgYB1EouV4g1V1wJ73c45Aq26J+CnlK+dl3d5jG5FpK6DosQ1A5kw\nuGzHTqcrND7g3jXJMWw3FWr+nH//fe2f8/drQ6A5UfytaBbXL5rE3eWFAXXWrUPM\n468swC6mNuOoZahkAx05U4lojtNj5QqEoMSKD114MfgdkYhquckCTq2brwKBgQC5\ns1zS0II6xSvZw9YmhWj+gl0WvVduFWGcNZnE3SgyrddbnCp5VdIlbAASTx4ZC2Th\neXGUYh4CfC5ZRPFB96ywBxqggdQzEU1iHd8ctkWK9VCGh6cGIRqoTO2lCy/RW7Cp\n5ci+nls/uu2QZmqppS+vETgAfNPDOXs0vtUZUEs9/wKBgDNQonVvTTQIRbaRbxXu\neVqxAVYBb8PSPBjfigb4/sGzu4iYaxuCHOkA8AK9B9SmGjaQHJ4h9t+kJKe9xNie\nv7sG5pguzUyd+AJIafbeh2Iryva/Nw3Shb7Jl6EX/lX3o/B9hRziWKV0IvwCUF/1\niyxhUEyZT7ugi8eNl5zVJgmN\n-----END PRIVATE KEY-----\";\n    var ecdsap256Pem = @\"-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPHkoVMg7fVw+20dJ\niZrIo86ikidAv9V/ImB7q8QJ3f6hRANCAAShaGB2y+jNBGKsI+r4l+Bq82q+UVUn\nlPBvdBz9mGA32F9oosJ1s6mPmsasSI5FdG0B8sbQMLD7j5/8Lcjb1P4I\n-----END PRIVATE KEY-----\";\n    var ecdsap384Pem = @\"-----BEGIN PRIVATE KEY-----\nMIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBgquj404eo5PGToagO\ntXFnhf8/kryAfQFlNEqrruGrGrAmQWuHjDeG2yxnMYpgYrShZANiAASvXyCM6j2f\nn5ytuT/ekSiWcd1KoGexHWxXE7AVWfdXY0o2iJpZxRIZbqhiLfIruAxYFlvNnaGh\nUNEj76uLE5jR1xdH471mzsEPWrxi/CeTm0OyQ6yQg3pQH5FFVyCR1so=\n-----END PRIVATE KEY-----\";\n    var ecdsap521Pem = @\"-----BEGIN PRIVATE KEY-----\nMIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAGXO87cgkpAPLIWoc\nkZirXguaO7WeAFtO+z5TtfHyTLEgSUWlGhP1PZ3ZbyLf0ht6t4X46TQQn7Eyqkuy\nXgXZ0RihgYkDgYYABAAa9hQJavg/gAqUEIVoL1TucLMu1gCElMvX68BrJQoYdoNe\ngbR4mS/oiOdvU5zm4H2ABo6gDYo2Pl4W80lqL3nGdgAwdNN7udRi/A5wc39KvZ5w\nbbDmx/ly7kvagszIWafjG8Hzg5v5kKBbdYw9A+9pN2cbhWXug41xR1rLDOI6hFSn\nTA==\n-----END PRIVATE KEY-----\";\n\n    var server = new SshServer();\n    server.AddHostKey(\"rsa-sha2-256\", rsa2048BitPem);\n    server.AddHostKey(\"rsa-sha2-512\", rsa2048BitPem);\n    server.AddHostKey(\"ecdsa-sha2-nistp256\", ecdsap256Pem);\n    server.AddHostKey(\"ecdsa-sha2-nistp384\", ecdsap384Pem);\n    server.AddHostKey(\"ecdsa-sha2-nistp521\", ecdsap521Pem);\n\n    server.ConnectionAccepted += server_ConnectionAccepted;\n\n    server.Start();\n\n    Task.Delay(-1).Wait();\n}\n\nstatic void server_ConnectionAccepted(object sender, Session e)\n{\n    Console.WriteLine(\"Accepted a client.\");\n\n    e.ServiceRegistered += e_ServiceRegistered;\n    e.KeysExchanged += e_KeysExchanged;\n}\n\nprivate static void e_KeysExchanged(object sender, KeyExchangeArgs e)\n{\n    foreach (var keyExchangeAlg in e.KeyExchangeAlgorithms)\n    {\n        Console.WriteLine(\"Key exchange algorithm: {0}\", keyExchangeAlg);\n    }\n}\n\nstatic void e_ServiceRegistered(object sender, SshService e)\n{\n    var session = (Session)sender;\n    Console.WriteLine(\"Session {0} requesting {1}.\",\n        BitConverter.ToString(session.SessionId).Replace(\"-\", \"\"), e.GetType().Name);\n\n    if (e is UserAuthService)\n    {\n        var service = (UserAuthService)e;\n        service.UserAuth += service_UserAuth;\n    }\n    else if (e is ConnectionService)\n    {\n        var service = (ConnectionService)e;\n        service.CommandOpened += service_CommandOpened;\n        service.EnvReceived += service_EnvReceived;\n        service.PtyReceived += service_PtyReceived;\n        service.TcpForwardRequest += service_TcpForwardRequest;\n        service.WindowChange += Service_WindowChange;\n    }\n}\n\nstatic void Service_WindowChange(object sender, WindowChangeArgs e)\n{\n    // DEMO MiniTerm not support change window size\n}\n\nstatic void service_TcpForwardRequest(object sender, TcpRequestArgs e)\n{\n    Console.WriteLine(\"Received a request to forward data to {0}:{1}\", e.Host, e.Port);\n\n    var allow = true;  // func(e.Host, e.Port, e.AttachedUserAuthArgs);\n\n    if (!allow)\n        return;\n\n    var tcp = new TcpForwardService(e.Host, e.Port, e.OriginatorIP, e.OriginatorPort);\n    e.Channel.DataReceived += (ss, ee) =\u003e tcp.OnData(ee);\n    e.Channel.CloseReceived += (ss, ee) =\u003e tcp.OnClose();\n    tcp.DataReceived += (ss, ee) =\u003e e.Channel.SendData(ee);\n    tcp.CloseReceived += (ss, ee) =\u003e e.Channel.SendClose();\n    tcp.Start();\n}\n\nstatic void service_PtyReceived(object sender, PtyArgs e)\n{\n    Console.WriteLine(\"Request to create a PTY received for terminal type {0}\", e.Terminal);\n    windowWidth = (int)e.WidthChars;\n    windowHeight = (int)e.HeightRows;\n}\n\nstatic void service_EnvReceived(object sender, EnvironmentArgs e)\n{\n    Console.WriteLine(\"Received environment variable {0}:{1}\", e.Name, e.Value);\n}\n\nstatic void service_UserAuth(object sender, UserAuthArgs e)\n{\n    Console.WriteLine(\"Client {0} fingerprint: {1}.\", e.KeyAlgorithm, e.Fingerprint);\n\n    e.Result = true;\n}\n\nstatic void service_CommandOpened(object sender, CommandRequestedArgs e)\n{\n    Console.WriteLine($\"Channel {e.Channel.ServerChannelId} runs {e.ShellType}: \\\"{e.CommandText}\\\", client key SHA256:{e.AttachedUserAuthArgs.Fingerprint}.\");\n\n    e.Agreed = true;  // func(e.ShellType, e.CommandText, e.AttachedUserAuthArgs);\n\n    if (!e.Agreed)\n        return;\n\n    if (e.ShellType == \"shell\")\n    {\n        // requirements: Windows 10 RedStone 5, 1809\n        // also, you can call powershell.exe\n        var terminal = new Terminal(\"cmd.exe\", windowWidth, windowHeight);\n\n        e.Channel.DataReceived += (ss, ee) =\u003e terminal.OnInput(ee);\n        e.Channel.CloseReceived += (ss, ee) =\u003e terminal.OnClose();\n        terminal.DataReceived += (ss, ee) =\u003e e.Channel.SendData(ee);\n        terminal.CloseReceived += (ss, ee) =\u003e e.Channel.SendClose(ee);\n\n        terminal.Run();\n    }\n    else if (e.ShellType == \"exec\")\n    {\n        var parser = new Regex(@\"(?\u003ccmd\u003egit-receive-pack|git-upload-pack|git-upload-archive) \\'/?(?\u003cproj\u003e.+)\\.git\\'\");\n        var match = parser.Match(e.CommandText);\n        var command = match.Groups[\"cmd\"].Value;\n        var project = match.Groups[\"proj\"].Value;\n\n        var git = new GitService(command, project);\n\n        e.Channel.DataReceived += (ss, ee) =\u003e git.OnData(ee);\n        e.Channel.CloseReceived += (ss, ee) =\u003e git.OnClose();\n        git.DataReceived += (ss, ee) =\u003e e.Channel.SendData(ee);\n        git.CloseReceived += (ss, ee) =\u003e e.Channel.SendClose(ee);\n\n        git.Start();\n    }\n    else if (e.ShellType == \"subsystem\")\n    {\n        if (e.CommandText == \"sftp\")\n        {\n            var sftp = new SftpService(OperatingSystem.IsWindows() ? @\"C:\\\" : @\"/\");\n            e.Channel.DataReceived += (ss, ee) =\u003e sftp.OnData(ee);\n            e.Channel.CloseReceived += (ss, ee) =\u003e sftp.OnClose();\n            sftp.DataReceived += (ss, ee) =\u003e e.Channel.SendData(ee);\n        }\n    }\n}\n```\n\n### Generate private key\n```cs\nKeyGenerator.GenerateRsaKeyPem(2048); \\\\ generate rsa key with 2048 bits\nKeyGenerator.GenerateECDsaKeyPem(\"nistp256\"); \\\\ generate ecdsa key with curve nistp256\nKeyGenerator.ConvertRsaBase64KeyToPem(\"base64\"); \\\\ convert old rsa base64 key to pem format\n```\n\n---\n### License\nThe MIT license\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faimeast%2Ffxssh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faimeast%2Ffxssh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faimeast%2Ffxssh/lists"}