RouteHardenHire us
← Back to blog
Network Hardening··6 min read

Disabling and replacing weak crypto algorithms server-wide

How to remove weak SSH-era crypto safely, where system-wide crypto policy really applies, and how to verify you modernized the server instead of just breaking access.

Weak crypto is usually not a tuning problem. It is a migration problem.

By the time someone asks how to "disable weak SSH ciphers," the real situation is normally one of these:

  • an audit scanner found legacy algorithms
  • an old client still depends on them
  • the server has accumulated compatibility settings nobody wants to own

The right goal is not "make the scan green." It is "replace old negotiation baggage with current defaults, and understand what still refuses to move."

That distinction matters because scanner remediation advice is often written as if the act of hiding an algorithm from one handshake were equivalent to modernizing a service. It is not. If an old dependency still exists, it will show up somewhere else: a second host, a fallback config, a jump box, an emergency exception nobody documents.

What "server-wide" actually means

On Linux, "server-wide crypto policy" is more true on some platforms than others.

The cleanest model is on RHEL-family systems. Red Hat's crypto-policies architecture covers multiple protocol families at the base-OS level, including TLS, IPSec, DNSSEC, and Kerberos. You can inspect or switch policy with:

sudo update-crypto-policies --show
sudo update-crypto-policies --set FUTURE

That is real leverage.

But it is not magic. Red Hat also documents that some software, including Go applications and GnuPG, does not fully follow the system-wide policy. That is the first lesson here: a platform crypto policy is powerful, but it is not universal.

On Debian and Ubuntu, the honest model is often still per-service hardening. That is especially true for SSH, which is usually where the first weak-algorithm finding shows up anyway.

So when people say "server-wide," read it as "as wide as this platform and this application stack actually support." Anything stronger is marketing.

SSH is the service most people should harden directly

OpenSSH gives you explicit server-side controls for the things scanners actually report:

  • Ciphers
  • KexAlgorithms
  • MACs
  • HostKeyAlgorithms
  • PubkeyAcceptedAlgorithms

Those are all documented in the canonical sshd_config reference.

Before changing anything, inspect what your current build even supports:

ssh -Q cipher
ssh -Q mac
ssh -Q kex
sshd -T | egrep 'ciphers|macs|kexalgorithms|hostkeyalgorithms|pubkeyacceptedalgorithms'

The first three show what the installed OpenSSH build knows about. The sshd -T line shows what your daemon will effectively offer after config is merged.

That distinction matters because people often edit the config based on an Internet example without first checking whether the local build, package version, or distro defaults actually match.

A hardened SSH override

If you want a clean OpenSSH-only modernization pass, a small override is usually enough:

# /etc/ssh/sshd_config.d/10-crypto.conf
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
KexAlgorithms sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com,curve25519-sha256,curve25519-sha256@libssh.org
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,ecdsa-sha2-nistp256,rsa-sha2-512,rsa-sha2-256
PubkeyAcceptedAlgorithms ssh-ed25519,ecdsa-sha2-nistp256,rsa-sha2-512,rsa-sha2-256

That does two useful things:

  1. It makes the preferred algorithms explicit.
  2. It makes the legacy ones absent on purpose.

Do not treat this as a magic incantation. Treat it as a starting policy that you verify from a second host before you close the original session.

This should live next to the broader guidance in /blog/ssh-hardening-vpn-bastion, not replace it.

And if your audit tooling keeps flagging weak host keys or MACs after you thought you were done, that is not a reason to add more syntax. It is a reason to prove whether you changed the effective configuration, the exposed host, or merely the file you wished were authoritative.

The compatibility trap

Upstream OpenSSH's own legacy guidance is unusually sane here. It says the best fix is to upgrade the remote software or replace the weak key type, not to keep legacy algorithms enabled forever.

It also documents the +algo syntax for temporary re-enablement. That is useful during migrations because it lets you restore access to one old dependency while still preferring stronger defaults for everything else.

That is what this looks like:

Host ancient-box
    KexAlgorithms +diffie-hellman-group14-sha1

But the key word is temporary.

The wrong lesson is "OpenSSH lets me re-enable old algorithms, therefore I should." The right lesson is "I have a controlled way to keep one fragile system reachable while I remove the underlying dependency."

Weak negotiation should live on your decommission queue, not inside your permanent baseline.

This is especially true for SHA-1-era and DSS-era baggage. If the only thing keeping it alive is fear of an outage, that is an argument for controlled migration planning, not for normalizing the exception forever.

A sane migration sequence

If you want to remove weak algorithms without locking yourself out, the sequence matters more than the specific config spelling.

1. Inventory first

Use OpenSSH introspection locally, then check what the server actually offers remotely.

Nmap's ssh2-enum-algos script is perfect for this:

nmap --script ssh2-enum-algos -p 22 vps.example.com

That gives you a before-and-after view that is far more useful than trusting the config file by eye.

2. Remove one class at a time

Do not simultaneously change ciphers, KEX, MACs, and host-key algorithms on a host that is important to you. Change one category, test, then move to the next.

3. Keep a rollback path

This is the same rollout discipline as every good SSH change:

  • keep one session open
  • test from a second client
  • verify with sshd -t
  • reload, do not blindly restart

4. Replace the dependency, not just the symptom

If one legacy appliance forces you to keep SHA-1-era negotiation alive, the problem is the appliance, not the modern clients.

That is the opinion that matters here. A lot of "backward compatibility" is just unowned technical debt wearing a polite name tag.

Sometimes the right answer is to scope the exception to one host stanza or one management path and keep the public baseline clean. If you can isolate the compatibility damage, do it.

Verification beats aspiration

After the change:

sshd -T | egrep 'ciphers|macs|kexalgorithms|hostkeyalgorithms|pubkeyacceptedalgorithms'
nmap --script ssh2-enum-algos -p 22 vps.example.com

If you are hardening more than SSH, use the same principle on the rest of the stack. Nmap's service/version detection is useful because it tells you whether you modernized the actual exposed service or just edited a file and hoped.

On RHEL-family systems, platform policy is worth using. But even there, do not overclaim. "System-wide" does not mean every binary on the box shares one obedient crypto brain.

My rule is simple:

  • prefer modern defaults
  • use temporary compatibility only to preserve access during migration
  • verify what the network sees
  • retire the dependency, not just the finding

That is how you remove weak crypto without turning your estate into a museum of carefully curated exceptions.