Skip to content

darinkes/SshNet.Keygen

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

115 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SshNet.Keygen

SSH.NET Extension to generate and export Authentication Keys in OpenSSH and PuTTY v2 and v3 Format.

License NuGet Nuget

.NET-Ubuntu .NET-Windows NuGet

.NET Frameworks

  • .NET 4.8
  • netstandard 2.0
  • .NET 8.0

Keys

  • ssh-ed25519
  • ecdsa-sha2-nistp256
  • ecdsa-sha2-nistp384
  • ecdsa-sha2-nistp521
  • ssh-rsa with 2048, 3072, 4096 or 8192 KeyLength

Fingerprinting

  • Get Key Fingerprint as MD5, SHA1, SHA256, SHA384 or SHA512

Key Encryption

OpenSSH

  • None
  • AES256-ctr
  • AES256-cbc

PuTTY

  • None
  • AES256-cbc

Certificates

  • Sign OpenSSH user and host certificates (SshCertificateBuilder)

.NET Key Interop

  • Import System.Security.Cryptography keys and PEM files (SshKey.FromKey, SshKey.FromPem, SshKey.FromEd25519)

Usage Examples

Builder API

SshKey.Builder() gives a fluent alternative to SshKeyGenerateInfo. Set the options you care about, then call a Generate overload (in-memory, to a Stream, or to a file).

// RSA-2048 in memory (defaults)
var key = SshKey.Builder().Generate();

// ECDSA-384 with a comment, in memory
var key = SshKey.Builder(SshKeyType.ECDSA)
    .WithKeyLength(384)
    .WithComment("me@host")
    .Generate();

// Passphrase-protected Ed25519 written to a file
var key = SshKey.Builder(SshKeyType.ED25519)
    .WithPassphrase("12345")
    .Generate("test.key");

// PuTTY v3 with custom encryption, written to a file
var key = SshKey.Builder(SshKeyType.RSA)
    .WithKeyLength(4096)
    .WithFormat(SshKeyFormat.PuTTYv3)
    .WithEncryption(new SshKeyEncryptionAes256("12345"))
    .Generate("test.ppk", FileMode.Create);

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Sign an OpenSSH Certificate

SshCertificateBuilder mints and signs OpenSSH certificates (the ssh-keygen -s step) for user or host authentication. Point it at the public key to certify, set the certificate fields, and sign with your CA key.

var caKey = new PrivateKeyFile("ca");            // your CA private key
var userKey = new PrivateKeyFile("id_ed25519");  // the key to certify

var certificate = new SshCertificateBuilder(userKey)
    .WithSerial(1)
    .WithKeyId("alice@example.com")
    .WithPrincipal("alice")
    .WithValidity(DateTime.UtcNow, DateTime.UtcNow.AddHours(8))
    .SignWith(caKey);

// OpenSSH expects the certificate next to the key as <key>-cert.pub
File.WriteAllText("id_ed25519-cert.pub", certificate.ToOpenSshPublicFormat());

Console.WriteLine(certificate.Fingerprint());

The CA and the key to certify can be freshly generated too, and host certificates work the same way:

var ca = SshKey.Generate(new SshKeyGenerateInfo(SshKeyType.ED25519));
var host = SshKey.Generate(new SshKeyGenerateInfo(SshKeyType.ED25519));

var hostCert = new SshCertificateBuilder(host)
    .WithType(SshCertificateType.Host)
    .WithPrincipal("host.example.com")
    .ValidForever()
    .SignWith(ca);

User certificates get OpenSSH's default extensions (permit-pty, permit-user-rc, …). Override them with WithExtension, and add restrictions like force-command or source-address with WithCriticalOption. A server trusts these certificates when its TrustedUserCAKeys names the CA public key (user certs), or a client's known_hosts @cert-authority line does (host certs). The resulting certificate can be authenticated with directly, or offered through a key agent - see SshNet.Agent.

Generate an RSA-2048 Key in File, Show the Public Key and Connect with the Private Key

var key = SshKey.Generate("test.key", FileMode.Create);

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an RSA-2048 Key in PuTTY File, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo
{
    KeyFormat = SshKeyFormat.PuTTYv3
};
var key = SshKey.Generate("test.ppk", FileMode.Create, keyInfo);

var publicKey = key.ToPublic(SshKeyFormat.OpenSSH);
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an password protected RSA-2048 Key in File, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo
{
    Encryption = new SshKeyEncryptionAes256("12345")
};
var key = SshKey.Generate("test.key", FileMode.Create, keyInfo);

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an password protected RSA-2048 Key in Putty v2 File, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo
{
    KeyFormat = SshKeyFormat.PuTTYv2,
    Encryption = new SshKeyEncryptionAes256("12345")
};
var key = SshKey.Generate("test.ppk", FileMode.Create, keyInfo);

var publicKey = key.ToPublic(SshKeyFormat.OpenSSH);
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an password protected RSA-2048 Key in Putty v3 File with own Argon Options, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo
{
    KeyFormat = SshKeyFormat.PuTTYv3,
    Encryption = new SshKeyEncryptionAes256("12345", new PuttyV3Encryption { KeyDerivation = ArgonKeyDerivation.Argon2d, Iterations = 64, DegreeOfParallelism = 44 })
};
var key = SshKey.Generate("test.ppk", FileMode.Create, keyInfo);

var publicKey = key.ToPublic(SshKeyFormat.OpenSSH);
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an RSA-2048 Key, Show the Public Key and Connect with the Private Key

var key = SshKey.Generate();

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an RSA-8192 Key, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo
{
    KeyLength = 8192
};
var key = SshKey.Generate(keyInfo);

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an ECDSA-256 Key, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo(SshKeyType.ECDSA);
var key = SshKey.Generate(keyInfo);

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Generate an ED25519 Key, Show the Public Key and Connect with the Private Key

var keyInfo = new SshKeyGenerateInfo(SshKeyType.ED25519);
var key = SshKey.Generate(keyInfo);

var publicKey = key.ToPublic();
var fingerprint = key.Fingerprint();

Console.WriteLine("Fingerprint: {0}", fingerprint);
Console.WriteLine("Add this to your .ssh/authorized_keys on the SSH Server: {0}", publicKey);
Console.ReadLine();

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();
Console.WriteLine(client.RunCommand("hostname").Result);

Export an existing Key from SSH.NET

var keyFile = new PrivateKeyFile("test.key");

var privateKey = keyFile.ToOpenSshFormat();
var publicKey =  keyFile.ToPublic();

Console.WriteLine("Private Key: {0}", privateKey);
Console.WriteLine("Public Key: {0}", publicKey);

Export an existing Key from SSH.NET with Encryption

var keyFile = new PrivateKeyFile("test.key");

var privateKey = keyFile.ToOpenSshFormat("12345");
var puttyKey = keyFile.ToPuttyFormat("12345");
var publicKey =  keyFile.ToPublic();
var puttyPublicKey =  keyFile.ToPuttyPublicFormat();

Console.WriteLine("Private Key: {0}", privateKey);
Console.WriteLine("Putty Private Key: {0}", puttyKey);
Console.WriteLine("Public Key: {0}", publicKey);
Console.WriteLine("Putty Public Key: {0}", puttyPublicKey);

Use an existing .NET Key

SshKey.FromKey wraps a BCL RSA or ECDsa key (NIST curves) as an SSH.NET key, SshKey.FromEd25519 takes a raw 32-byte seed (or 64-byte expanded key), and SshKey.FromPem imports a PEM (PKCS#1, SEC1 or PKCS#8, optionally encrypted). The result can be exported or used to connect like any generated key.

using var rsa = RSA.Create(2048);
var key = SshKey.FromKey(rsa, "me@host");

// or from a PEM file
var pemKey = SshKey.FromPem(File.ReadAllText("key.pem"), "passphrase");

Console.WriteLine("Public Key: {0}", key.ToPublic());

using var client = new SshClient("ssh.foo.com", "root", key);
client.Connect();

SshKey.FromPem requires .NET 8 or later; on .NET 4.8 and netstandard 2.0 it throws PlatformNotSupportedException.

Sign and Verify (SSH signatures)

Create and verify detached signatures in the OpenSSH SSHSIG format β€” the same format ssh-keygen -Y sign produces and ssh-keygen -Y verify checks. RSA, ECDSA and Ed25519 keys are supported.

var keyFile = new PrivateKeyFile("test.key");
var data = File.ReadAllBytes("test.txt");

// armored -----BEGIN SSH SIGNATURE----- text
var signature = keyFile.Signature(data);

// or sign a file directly (writes test.txt.sig next to it)
keyFile.SignatureFile("test.txt");

// the namespace defaults to "file"; pass your own (OpenSSH's -n) to bind the signature to it
var gitSignature = keyFile.Signature(data, "git");

Verifying β€” check who signed, not just that the signature is valid:

// authenticate against a public key you trust
var trusted = ((KeyHostAlgorithm)new PrivateKeyFile("signer.key").HostKeyAlgorithms.First()).Key;
if (SshSignature.Verify(data, signature, trusted))
    Console.WriteLine("signed by the trusted key");

// or get the signer back and match it against your own allow-list
if (SshSignature.Verify(data, signature, out var signer))
    Console.WriteLine($"valid signature from a {signer} key");

// verify a file's signature (optionally with an expected signer / namespace)
SshSignature.VerifyFile("test.txt", "test.txt.sig");

SshSignature.Verify(data, signature) proves the signature is valid, not that a trusted party made it β€” the public key is taken from the signature itself, so any key verifies. To authenticate the signer, pass the expected public key (or use the out overload and match the returned key against your trust set), just as ssh-keygen -Y verify requires an allowed_signers file. The namespace is enforced and defaults to file.

About

SSH.NET Extension to generate and export Authentication Keys in OpenSSH and PuTTY Format. πŸ”‘

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages