Loading learning content...
Every SSH connection you've ever made—whether typing ssh server.example.com or pushing code to GitHub—executes a sophisticated cryptographic protocol in milliseconds. Within 100-200 milliseconds, two machines that have never communicated establish provable identities, negotiate encryption algorithms, derive shared secrets without transmitting them, and create an encrypted channel impervious to eavesdropping.
This seamless experience conceals remarkable complexity. The SSH protocol orchestrates public key cryptography, symmetric encryption, message authentication, and careful sequencing to achieve security that was once thought impossible over untrusted networks.
By the end of this page, you will understand SSH-2 protocol mechanics at the wire level: the transport layer protocol, packet structure, key exchange algorithms, encryption negotiation, and the message flows that establish secure connections. You'll gain the depth to debug SSH issues, evaluate security configurations, and understand protocol traces.
SSH-2 defines three core protocols that operate as a layered stack. This separation enables independent evolution and allows different implementations to share common components.
Transport Layer Protocol (RFC 4253)
The foundation providing:
User Authentication Protocol (RFC 4252)
Builds on the transport layer to:
Connection Protocol (RFC 4254)
Provides:
SSH-2 is standardized in IETF RFCs 4250-4256. RFC 4250 defines protocol numbers, RFC 4251 describes architecture, RFC 4252 covers authentication, RFC 4253 specifies the transport layer, RFC 4254 defines the connection protocol, RFC 4255 covers DNS for key fingerprints, and RFC 4256 defines keyboard-interactive authentication. These documents provide authoritative protocol specifications.
Every SSH communication after version string exchange uses a consistent packet format. Understanding this format is essential for protocol analysis and debugging.
Binary Packet Protocol:
SSH packets have this structure:
┌──────────────────────────────────────────────────────────────────────┐│ SSH Binary Packet │├──────────────────────────────────────────────────────────────────────┤│ packet_length │ 4 bytes │ Length of packet (excluding self+MAC)│├──────────────────┼───────────┼───────────────────────────────────────┤│ padding_length │ 1 byte │ Length of random padding │├──────────────────┼───────────┼───────────────────────────────────────┤│ payload │ Variable │ Actual packet data │├──────────────────┼───────────┼───────────────────────────────────────┤│ random_padding │ Variable │ Minimum 4 bytes, max 255 bytes │├──────────────────┼───────────┼───────────────────────────────────────┤│ MAC │ Variable │ Message Authentication Code │└──────────────────────────────────────────────────────────────────────┘ Total Size = 4 + 1 + payload + padding = as stated in packet_length + 4MAC appended after encryption (encrypt-then-MAC modes)Field Details:
packet_length (4 bytes): The total length of the packet excluding this field and the MAC. This is the first value encrypted (except during key exchange).
padding_length (1 byte): The amount of random padding appended to align the encrypted block to cipher block size boundaries. The total packet (excluding MAC) must be a multiple of the cipher block size or 8 bytes, whichever is larger.
payload (variable): The actual SSH message. The first byte of the payload is always the message type identifier.
random_padding (4-255 bytes): Random bytes that:
MAC (variable): Message Authentication Code computed over:
For AEAD ciphers (AES-GCM, ChaCha20-Poly1305), the MAC is integrated into the cipher operation.
| Range | Category | Examples |
|---|---|---|
| 1-19 | Transport Layer Generic | SSH_MSG_DISCONNECT (1), SSH_MSG_IGNORE (2), SSH_MSG_DEBUG (4) |
| 20-29 | Algorithm Negotiation | SSH_MSG_KEXINIT (20), SSH_MSG_NEWKEYS (21) |
| 30-49 | Key Exchange Methods | SSH_MSG_KEXDH_INIT (30), SSH_MSG_KEXDH_REPLY (31) |
| 50-59 | User Authentication Generic | SSH_MSG_USERAUTH_REQUEST (50), SSH_MSG_USERAUTH_SUCCESS (52) |
| 60-79 | User Authentication Method-specific | SSH_MSG_USERAUTH_PK_OK (60) |
| 80-89 | Connection Protocol Generic | SSH_MSG_GLOBAL_REQUEST (80), SSH_MSG_CHANNEL_OPEN (90) |
| 90-127 | Channel-related | SSH_MSG_CHANNEL_DATA (94), SSH_MSG_CHANNEL_EOF (96) |
Each direction maintains an implicit 32-bit sequence number, starting at 0 and incrementing for every packet. This sequence number is included in MAC computation but never transmitted. An attacker cannot replay captured packets because the sequence number wouldn't match—the replay would have an incorrect MAC and be rejected.
Key exchange is the cryptographic heart of SSH, establishing shared secrets over an untrusted network. SSH-2 supports multiple key exchange algorithms, with the protocol selecting based on negotiated preferences.
Key Exchange Goals:
SSH_MSG_KEXINIT Structure:
This message initiates algorithm negotiation:
byte SSH_MSG_KEXINIT (20)byte[16] cookie (random bytes - prevent replay)name-list kex_algorithmsname-list server_host_key_algorithmsname-list encryption_algorithms_client_to_servername-list encryption_algorithms_server_to_clientname-list mac_algorithms_client_to_servername-list mac_algorithms_server_to_clientname-list compression_algorithms_client_to_servername-list compression_algorithms_server_to_clientname-list languages_client_to_servername-list languages_server_to_clientboolean first_kex_packet_followsuint32 0 (reserved)Algorithm Selection:
For each category, the first algorithm in the client's list that also appears in the server's list is selected. This gives clients preference control while ensuring compatibility.
Exchange Hash Computation:
The exchange hash H binds the entire negotiation:
H = hash(V_C || V_S || I_C || I_S || K_S || Q_C || Q_S || K) Where: V_C = Client version string (e.g., "SSH-2.0-OpenSSH_9.0") V_S = Server version string I_C = Client's KEXINIT payload I_S = Server's KEXINIT payload K_S = Server's public host key Q_C = Client's ephemeral DH/ECDH public value Q_S = Server's ephemeral DH/ECDH public value K = Shared secret from DH/ECDHThe server signs H with its host private key. This signature proves:
Session Key Derivation:
From K (shared secret) and H (exchange hash), SSH derives multiple keys:
| Key | Derivation | Purpose |
|---|---|---|
| Initial IV client→server | HASH(K || H || "A" || session_id) | Encryption initialization vector |
| Initial IV server→client | HASH(K || H || "B" || session_id) | Encryption initialization vector |
| Encryption key client→server | HASH(K || H || "C" || session_id) | Symmetric encryption |
| Encryption key server→client | HASH(K || H || "D" || session_id) | Symmetric encryption |
| Integrity key client→server | HASH(K || H || "E" || session_id) | MAC computation |
| Integrity key server→client | HASH(K || H || "F" || session_id) | MAC computation |
Notice that session keys derive from ephemeral DH/ECDH values that are discarded after key exchange. Even if an attacker later obtains the server's host private key, they cannot decrypt past sessions—those sessions used ephemeral keys that no longer exist. This is forward secrecy: past traffic remains secure even if long-term keys are compromised.
SSH-2 supports multiple key exchange algorithms. Modern deployments prefer elliptic curve methods for their combination of security and efficiency.
Curve25519 (curve25519-sha256@libssh.org, curve25519-sha256)
The current gold standard for SSH key exchange:
| Algorithm | Type | Security Level | Status | Notes |
|---|---|---|---|---|
| curve25519-sha256 | ECDH | ~128-bit | Preferred | Fast, secure, widely supported |
| ecdh-sha2-nistp256 | ECDH | ~128-bit | Acceptable | NIST curve, some concerns about constants |
| ecdh-sha2-nistp384 | ECDH | ~192-bit | Acceptable | Higher security margin |
| ecdh-sha2-nistp521 | ECDH | ~256-bit | Acceptable | Highest NIST curve security |
| diffie-hellman-group16-sha512 | DH | ~128-bit | Acceptable | 4096-bit DH group |
| diffie-hellman-group18-sha512 | DH | ~192-bit | Acceptable | 8192-bit DH group |
| diffie-hellman-group14-sha256 | DH | ~112-bit | Legacy | 2048-bit, minimum acceptable |
| diffie-hellman-group1-sha1 | DH | ~80-bit | Deprecated | 1024-bit, insecure |
Diffie-Hellman Primer:
Classic DH operates in a multiplicative group modulo a large prime p:
Both derive the same K without transmitting x or y.
Elliptic Curve Diffie-Hellman:
ECDH achieves equivalent security with smaller values:
Curve25519 specifically is designed for:
diffie-hellman-group1-sha1 uses only 1024-bit DH and SHA-1, both considered weak. diffie-hellman-group-exchange-sha1 shares the SHA-1 weakness. Modern configurations should explicitly disable these algorithms to prevent downgrade attacks.
After key exchange completes and SSH_MSG_NEWKEYS is exchanged, all traffic uses the negotiated encryption and integrity algorithms with derived session keys.
Authenticated Encryption with Associated Data (AEAD):
Modern SSH prefers AEAD ciphers that combine encryption and integrity in a single operation:
| Algorithm | Type | Key Size | Status | Notes |
|---|---|---|---|---|
| chacha20-poly1305@openssh.com | AEAD | 256-bit | Preferred | Fast on CPUs without AES-NI |
| aes256-gcm@openssh.com | AEAD | 256-bit | Preferred | Fast with hardware AES support |
| aes128-gcm@openssh.com | AEAD | 128-bit | Preferred | Smaller key, still secure |
| aes256-ctr | Stream | 256-bit | Acceptable | Requires separate MAC |
| aes192-ctr | Stream | 192-bit | Acceptable | Requires separate MAC |
| aes128-ctr | Stream | 128-bit | Acceptable | Requires separate MAC |
| aes256-cbc | Block | 256-bit | Deprecated | Vulnerable to padding oracle |
| 3des-cbc | Block | 168-bit | Deprecated | Slow, potential vulnerabilities |
ChaCha20-Poly1305:
Daniel Bernstein's cipher design, adopted by OpenSSH:
AES-GCM:
NIST standardized AEAD mode:
Non-AEAD Ciphers (Legacy):
Older configurations use separate encryption and MAC:
| Algorithm | Tag Size | Status | Notes |
|---|---|---|---|
| hmac-sha2-512-etm@openssh.com | 512-bit | Preferred | Encrypt-then-MAC mode |
| hmac-sha2-256-etm@openssh.com | 256-bit | Preferred | Encrypt-then-MAC mode |
| hmac-sha2-512 | 512-bit | Acceptable | Encrypt-and-MAC (weaker) |
| hmac-sha2-256 | 256-bit | Acceptable | Encrypt-and-MAC |
| hmac-sha1 | 160-bit | Deprecated | SHA-1 weakness concerns |
| hmac-md5 | 128-bit | Deprecated | MD5 is broken |
The -etm@ variants compute MAC after encryption, providing better security than encrypt-and-MAC. ETM prevents attacks where manipulated ciphertext fools the MAC check. When using non-AEAD ciphers, always prefer ETM variants.
Server authentication relies on host keys—cryptographic key pairs that identify servers. The server's public key is verified against known keys, and the private key signs the key exchange to prove identity.
Host Key Verification:
When connecting to a new server, SSH clients display the host key fingerprint:
The authenticity of host 'server.example.com (192.0.2.1)' can't be established.
ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
Are you sure you want to continue connecting (yes/no/[fingerprint])?
This "Trust on First Use" (TOFU) model establishes initial trust. Subsequent connections verify the server presents the same key—a changed key triggers a warning indicating potential man-in-the-middle attack.
| Key Type | Algorithm | Key Size | Status | Notes |
|---|---|---|---|---|
| ssh-ed25519 | EdDSA | 256-bit | Preferred | Fast, secure, small signatures |
| ecdsa-sha2-nistp256 | ECDSA | 256-bit | Acceptable | NIST P-256 curve |
| ecdsa-sha2-nistp384 | ECDSA | 384-bit | Acceptable | Higher security margin |
| ecdsa-sha2-nistp521 | ECDSA | 521-bit | Acceptable | Highest NIST security |
| rsa-sha2-512 | RSA | ≥3072-bit | Acceptable | SHA-512 signatures |
| rsa-sha2-256 | RSA | ≥3072-bit | Acceptable | SHA-256 signatures |
| ssh-rsa | RSA | ≥2048-bit | Deprecated | SHA-1 signatures, disabled by default |
| ssh-dss | DSA | 1024-bit | Deprecated | Fixed size, weak |
Ed25519: The Modern Choice
Ed25519 offers compelling advantages:
RSA Considerations:
RSA remains widely deployed but requires attention:
Host Key Storage:
Servers store host keys in /etc/ssh/:
ssh_host_ed25519_key / ssh_host_ed25519_key.pubssh_host_rsa_key / ssh_host_rsa_key.pubClients store known host keys in ~/.ssh/known_hosts:
server.example.com ssh-ed25519 AAAA...base64-encoded-public-key...
Never ignore "REMOTE HOST IDENTIFICATION HAS CHANGED" warnings. This could indicate: (1) Server reinstallation or key regeneration—verify with administrator, (2) Man-in-the-middle attack—do not connect, or (3) DNS hijacking—verify IP address. Blindly accepting changed host keys defeats SSH's server authentication.
Long-running SSH sessions must manage cryptographic resources to maintain security. SSH supports rekeying—performing a new key exchange during an active session to refresh session keys.
Why Rekey?
OpenSSH Rekeying Defaults:
| Threshold | Trigger | Default Value |
|---|---|---|
| Data volume | Bytes transmitted with current keys | 1-4 GB (cipher-dependent) |
| Time | Seconds since last key exchange | 3600 (1 hour) or 0 (disabled) |
| Packet count | Approaching sequence number wrap | ~2^31 packets |
Rekeying Process:
Rekeying follows the same protocol as initial key exchange, but within the encrypted session:
The original session identifier remains constant—it binds the entire session to the initial key exchange.
Configuration Options:
# In ssh_config or sshd_config:
RekeyLimit 1G 1h # Rekey after 1GB or 1 hour, whichever first
RekeyLimit 500M 30m # More aggressive: 500MB or 30 minutes
RekeyLimit default # Use cipher-specific defaults
Rekeying is transparent to applications using the SSH connection. The shell session continues uninterrupted, file transfers proceed without pause. Users only notice rekeying if they enable verbose logging, where they'll see 'Rekeying...' messages.
We've explored SSH protocol mechanics at the wire level—from packet structure to key exchange to encryption algorithms. Let's consolidate the essential knowledge:
What's next:
With protocol mechanics understood, we'll explore SSH authentication methods in detail. The next page examines password authentication, public key authentication, certificates, and multi-factor configurations—the mechanisms that prove user identity after the encrypted channel is established.
You now understand SSH-2 protocol mechanics—packet format, key exchange, algorithm negotiation, and session management. This knowledge enables you to configure SSH securely, debug connection issues, and evaluate the security of SSH deployments.