How to Programmatically List Supported SSH Algorithms (MACs/Ciphers/Kex) for Security Auditing


1 views

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