SSH.NET Extension to generate and export Authentication Keys in OpenSSH and PuTTY v2 and v3 Format.
- .NET 4.8
- netstandard 2.0
- .NET 8.0
- ssh-ed25519
- ecdsa-sha2-nistp256
- ecdsa-sha2-nistp384
- ecdsa-sha2-nistp521
- ssh-rsa with 2048, 3072, 4096 or 8192 KeyLength
- Get Key Fingerprint as MD5, SHA1, SHA256, SHA384 or SHA512
- None
- AES256-ctr
- AES256-cbc
- None
- AES256-cbc
- Sign OpenSSH user and host certificates (
SshCertificateBuilder)
- Import
System.Security.Cryptographykeys and PEM files (SshKey.FromKey,SshKey.FromPem,SshKey.FromEd25519)
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();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.
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);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);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);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);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);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);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);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);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.FromPemrequires .NET 8 or later; on .NET 4.8 and netstandard 2.0 it throwsPlatformNotSupportedException.
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 theoutoverload and match the returned key against your trust set), just asssh-keygen -Y verifyrequires anallowed_signersfile. The namespace is enforced and defaults tofile.