The most straightforward method is using SSH's verbose mode. This reveals the negotiated algorithms during handshake:
ssh -vvv -o BatchMode=yes user@host 2>&1 | grep -E "kex:|ciphers:|macs:"
Example output showing supported algorithms:
debug2: ciphers ctos: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr
debug2: ciphers stoc: chacha20-poly1305@openssh.com,aes128-ctr,aes192-ctr,aes256-ctr
debug2: macs ctos: umac-64-etm@openssh.com,hmac-sha2-256-etm@openssh.com
debug3: send packet: type 20
debug1: SSH2_MSG_KEXINIT sent
The nmap
script engine provides more structured output:
nmap --script ssh2-enum-algos -p 22 target_host
Sample results in machine-readable format:
| ssh2-enum-algos:
| kex_algorithms: (11)
| curve25519-sha256
| ecdh-sha2-nistp256
| server_host_key_algorithms: (5)
| ssh-rsa
| rsa-sha2-256
| encryption_algorithms: (6)
| aes256-ctr
For integration into security tools, use this Python snippet:
import paramiko
transport = paramiko.Transport(('hostname', 22))
transport.connect()
print("KEX: ", transport.get_security_options().kex)
print("CIPHERS: ", transport.get_security_options().ciphers)
print("MACS: ", transport.get_security_options().macs)
transport.close()
On the server itself, check the active configuration:
sshd -T | grep -E "ciphers|macs|kexalgorithms"
Example showing configured algorithms:
kexalgorithms curve25519-sha256,ecdh-sha2-nistp256
ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
macs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
Combine these tools in a shell script for comprehensive reporting:
#!/bin/bash
echo "==== SSH ALGORITHM AUDIT ===="
echo "Generated: $(date)"
echo -e "\n[CLIENT TEST]"
ssh -vvv -o BatchMode=yes $1 2>&1 | awk '/kex:|ciphers:|macs:/ {print}'
echo -e "\n[NMAP SCAN]"
nmap --script ssh2-enum-algos -p 22 $1 | awk '/ssh2-enum-algos/,/^$/{print}'
When establishing an SSH connection, the client and server negotiate cryptographic algorithms through a process called algorithm negotiation. This includes:
- Key Exchange Algorithms (KexAlgorithms)
- Encryption Ciphers (Ciphers)
- Message Authentication Codes (MACs)
- Host Key Algorithms
The most reliable way to extract supported algorithms is through direct server interrogation:
# Using ssh-keyscan
ssh-keyscan -vv -p 22 your.server.com 2>&1 | grep -i "kex_algorithms\|ciphers\|macs"
# Using nmap scripting engine
nmap --script ssh2-enum-algos -p 22 your.server.com
For servers you control, you can parse the configuration directly:
# Extract configured algorithms
grep -E "^(KexAlgorithms|Ciphers|MACs) " /etc/ssh/sshd_config
# Get default values when not explicitly configured
sshd -T | grep -E "^(kexalgorithms|ciphers|macs)"
For non-interactive script usage:
ssh -o "StrictHostKeyChecking=no" \
-o "LogLevel=DEBUG3" \
-o "PreferredAuthentications=none" \
user@hostname true 2>&1 \
| grep -E "kex:|ciphers:|mac:" \
| awk -F: '{print $2}'
Here's a script that combines multiple approaches:
import subprocess
import re
def get_ssh_algorithms(hostname, port=22):
cmd = f"ssh -vvv -o StrictHostKeyChecking=no -o PreferredAuthentications=none -p {port} user@{hostname} true"
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
algorithms = {
'kex': re.findall(r'kex: algorithm: (.+)', result.stderr),
'ciphers': re.findall(r'ciphers ctos: (.+?)\n', result.stderr),
'macs': re.findall(r'mac ctos: (.+?)\n', result.stderr)
}
return algorithms
print(get_ssh_algorithms("example.com"))
To get key length information for host keys:
ssh-keyscan -p 22 your.server.com | while read line; do
echo "$line" | ssh-keygen -lf -;
done