SshKeyGenerator 2.0.0

dotnet add package SshKeyGenerator --version 2.0.0
                    
NuGet\Install-Package SshKeyGenerator -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="SshKeyGenerator" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="SshKeyGenerator" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="SshKeyGenerator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add SshKeyGenerator --version 2.0.0
                    
#r "nuget: SshKeyGenerator, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package SshKeyGenerator@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=SshKeyGenerator&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=SshKeyGenerator&version=2.0.0
                    
Install as a Cake Tool

DotNet Core SSH KeyGen

Build and test NuGet version (SshKeyGenerator)

Generate RSA SSH keys in managed C# on Windows, Linux, and macOS. Export private keys as OpenSSH or PKCS#1 RSA/PEM, with optional passphrase protection. The library has no runtime package dependencies and does not invoke external tools.

Project principles

  • Keep the library dependency-free. Production code must use the .NET Base Class Library (BCL), including System.Security.Cryptography, rather than third-party cryptography libraries such as Bouncy Castle or SSH.NET.
  • Keep key generation self-contained. Do not require external executables, native crypto packages, or platform-specific interop for generation or export.
  • Implement missing format support locally. Where the BCL does not provide an SSH encoding or derivation operation, use a focused managed implementation built on the BCL. The internal bcrypt_pbkdf implementation is one such case; preserve its attribution and license notices.
  • Verify interoperability independently. Third-party readers and command-line tools may be used in tests only; they must never become dependencies of the shipped library. Test/build packages must remain separate from runtime code.
  • Preserve existing functionality. Keep existing APIs and key formats compatible, and document any observable behavior changes.

Supported Platforms

  • .NET Framework 4.5.2 (legacy)
  • .NET Standard 2.0
  • .NET Standard 2.1
  • .NET 5.0
  • .NET 6.0
  • .NET 8.0
  • .NET 10.0

.NET Core applications can use the .NET Standard assets. Existing legacy targets are retained for compatibility; new applications should use a supported .NET runtime.

Installation

SshKeyGenerator is a library for .NET and is available on NuGet:

Install-Package SshKeyGenerator

or

dotnet add package SshKeyGenerator

Usage Example

using var keygen = new SshKeyGenerator.SshKeyGenerator(2048);

var privateKey = keygen.ToPrivateKey();
Console.WriteLine(privateKey);

var publicSshKey = keygen.ToRfcPublicKey();
Console.WriteLine(publicSshKey);

var publicSshKeyWithComment = keygen.ToRfcPublicKey("user@domain.com");
Console.WriteLine(publicSshKeyWithComment);

Passphrases and private key formats

using SshKeyGenerator;

using var keygen = new SshKeyGenerator.SshKeyGenerator(2048);
// Obtain this from your application's secret input mechanism.
string passphrase = GetPassphrase();

// Modern OpenSSH container: -----BEGIN OPENSSH PRIVATE KEY-----
string openSsh = keygen.ToPrivateKey(PrivateKeyFormat.OpenSsh, passphrase, "user@domain.com");
// Equivalent convenience method:
string sameFormat = keygen.ToOpenSshPrivateKey(passphrase, "user@domain.com");

// Traditional PKCS#1 PEM: -----BEGIN RSA PRIVATE KEY-----
string pem = keygen.ToPrivateKey(PrivateKeyFormat.Pem, passphrase);
// Equivalent convenience method:
string samePemFormat = keygen.ToPrivateKey(passphrase);

ToPrivateKey() still returns an unencrypted PKCS#1 PEM key. A null or empty passphrase exports an unencrypted key in either format. Whitespace and Unicode passphrases are preserved and encoded as UTF-8. Encryption applies to each export; it does not change the key pair or encrypt XML/CSP blob exports. OpenSSH comments are optional; CR, LF, and NUL are rejected.

Format Encryption with a passphrase Key derivation
OpenSSH (openssh-key-v1) AES-256-CBC bcrypt_pbkdf, 64 rounds, random 16-byte salt
RSA/PEM (PKCS#1) AES-256-CBC with PKCS#7 padding OpenSSL EVP_BytesToKey, MD5, random IV

Prefer OpenSSH for new integrations. The PEM derivation is the legacy algorithm required for compatibility with traditional encrypted RSA PRIVATE KEY files; it provides less resistance to passphrase guessing than bcrypt. This is not PKCS#8 (ENCRYPTED PRIVATE KEY). Every encrypted export uses fresh randomness.

ToRfcPublicKey() retains its existing name and returns a single-line OpenSSH authorized_keys entry, not an RFC4716 block. ToPublicKey() returns a SubjectPublicKeyInfo PUBLIC KEY PEM block. RSA is the key algorithm in both private key formats.

Save private keys using UTF-8 without a BOM and restrict file access (for example, chmod 600 id_rsa on Unix). To verify a saved key:

ssh-keygen -y -f id_rsa
# For RSA/PEM only:
openssl rsa -in id_rsa.pem -check -noout

Both commands prompt for an encrypted key's passphrase.

Sample Output

keygen.ToPrivateKey()
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAs1O/9F2XlZVaVWEUYfflxx0wDG9FE09hQF2wngA6EemHpe6I
hvdwvQ7obrZ85jSYdBxBRjNAYF3T9+wU+8w6m4qZCVYvqqRjszN8j3VwUBLzWilt
...
wDGzJIkmbhANi+252pH6PAuWjZPfz8COGA6QPPH0/khpHPj1LY4mi5Ubi3YT1uRo
dOGttjtkj9fLX5IQ81G9HR0MdT1Gd4fPenYPOUCgCPB5adpT1BB+
-----END RSA PRIVATE KEY-----
keygen.ToRfcPublicKey()
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCzU7/0XZeVlVpVYRRh9
...
+ohFsbcbAMcfLWGUdouyHvLvF21G0z50z2i2CrU7WW4WdrGGfxhU3TeRTXd7Skwk/K7iBBn3oc/xct generated-key
keygen.ToRfcPublicKey("user@domain.com")
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCzU7/0XZeVlVpVYRRh9
...
+ohFsbcbAMcfLWGUdouyHvLvF21G0z50z2i2CrU7WW4WdrGGfxhU3TeRTXd7Skwk/K7iBBn3oc/xct user@domain.com

Export Methods

There are three methods which can be used to export SSH key data for use by other libraries such as FxSsh:

  1. byte[] ToBlobs : Export as Blobs
  2. string ToB64Blob : Export blobs as base64 string
  3. string ToXml : Export as XML string

These legacy exports are unencrypted. CSP blob exports use a temporary RSACryptoServiceProvider and depend on platform support for that provider; PEM and OpenSSH generation use RSA.Create().

Export methods usage:

// Create a new instance 
var keygen = new SshKeyGenerator.SshKeyGenerator(4096);

// Get Base64 encoded keys with private key
var base64Keys = keygen.ToB64Blob(true);

// Use in a SSH server. e.g. FxSsh
var server = new SshServer();
server.AddHostKey("ssh-rsa", base64Keys);

Building and testing

Install the .NET 10 SDK (and the .NET 8 runtime to run both test targets).

dotnet build SshKeyGenerator.sln -c Release
dotnet test tests/SshKeyGenerator.Tests.csproj -c Release
# Also verify decryption using installed ssh-keygen and openssl (Unix shell):
SSH_KEYGEN_INTEROP_TESTS=1 dotnet test tests/SshKeyGenerator.Tests.csproj -c Release
# Exercise the .NET Standard implementation on a .NET runtime:
SSH_KEYGEN_INTEROP_TESTS=1 dotnet test tests/SshKeyGenerator.Tests.csproj -c Release -f net8.0 -p:KeyGeneratorTargetFramework=netstandard2.0
dotnet pack src/SshKeyGenerator.csproj -c Release

Tests use SSH.NET as an independent reader, check incorrect passphrases, compare public keys, and verify RSA signatures. Native-tool checks are opt-in locally and run in Linux/macOS CI. Framework 4.5.2 and .NET 5/6 assets are compile-checked; they require their respective runtimes for execution. See THIRD-PARTY-NOTICES.md for the vendored bcrypt license.

Releasing to NuGet

GitHub Actions builds and tests pull requests and pushes on Windows, Linux, and macOS. The Linux job saves the NuGet package as the nuget-build workflow artifact. Publishing a GitHub release triggers .github/workflows/release.yml, which reruns the full build/test matrix before packing and publishing to NuGet.org. Ordinary pushes and pull requests do not publish packages.

One-time setup for a package owner:

  1. Configure NuGet trusted publishing for repository owner ShawInnes, repository SshKeyGenerator, and workflow filename release.yml (without the .github/workflows/ prefix). Leave the environment field empty; the workflow does not use a GitHub environment. Scope publishing to the SshKeyGenerator package.
  2. Set the GitHub repository Actions variable NUGET_USER to the NuGet.org username that owns the policy (not an email address). The workflow exchanges its GitHub OIDC token for a short-lived NuGet API key; no stored API key is needed.
  3. Disable the old AppVeyor project/webhook and remove any required AppVeyor status check from branch protection if still configured. AppVeyor configuration and publishing have been removed from this repository.

For version 2.0.0, merge the changes into master, then create and publish a GitHub release targeting that commit with tag v2.0.0. The tag must equal v followed by the package version in src/SshKeyGenerator.csproj; a mismatch fails before publishing. Update <Version> in that project for subsequent releases.

The release workflow saves the package as the nuget-release artifact before publishing. A rerun skips an already-published package version; NuGet versions cannot be overwritten. This workflow does not create tags or GitHub releases.

References

Contributors

Thanks to the following contributors for their assistance with this library.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net452 is compatible.  net46 was computed.  net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.5.2

    • No dependencies.
  • .NETStandard 2.0

    • No dependencies.
  • .NETStandard 2.1

    • No dependencies.
  • net10.0

    • No dependencies.
  • net5.0

    • No dependencies.
  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on SshKeyGenerator:

Package Downloads
Slithin.Core

Package Description

GitHub repositories (1)

Showing the top 1 popular GitHub repositories that depend on SshKeyGenerator:

Repository Stars
furesoft/Slithin
A management application for the remarkable tablet
Version Downloads Last Updated
2.0.0 147 11/12/2026
1.1.51 1,000,533 1/29/2023
1.1.50 113,453 3/18/2022
1.1.49 1,600 3/18/2022
1.1.48 1,493 3/18/2022
1.1.47 1,571 3/18/2022
1.1.46 1,498 3/18/2022
1.1.45 3,852 2/5/2022
1.1.44 1,649 2/3/2022
1.1.43 1,629 2/3/2022
1.1.42 1,558 2/3/2022
1.1.40 188,332 3/25/2021
1.1.39 1,510 3/25/2021
1.1.38 7,072 1/16/2021
1.1.33 36,201 3/5/2020
1.1.32 1,721 3/5/2020
1.1.31 16,001 10/30/2019
1.1.19 5,569 7/21/2018
1.1.18 2,326 7/21/2018
1.1.17 2,311 7/21/2018
Loading failed