From 40d8f56c230791786af18b73d92f8189be1a7bf8 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Wed, 13 May 2026 18:29:39 +0800 Subject: [PATCH] fix: properly detect chacha20-poly1305 support before advertising it --- src/backend/utils/ssh-algorithms.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/backend/utils/ssh-algorithms.ts b/src/backend/utils/ssh-algorithms.ts index d2d5b273..d13ed8b1 100644 --- a/src/backend/utils/ssh-algorithms.ts +++ b/src/backend/utils/ssh-algorithms.ts @@ -1,7 +1,9 @@ import crypto from "crypto"; import type { ConnectConfig, CipherAlgorithm } from "ssh2"; -// Maps SSH cipher names to their OpenSSL equivalents (as used by ssh2 internally) +const availableCiphers = new Set(crypto.getCiphers()); + +// Maps SSH cipher names to their OpenSSL equivalents const SSH_CIPHER_SSL_NAME: Partial> = { "chacha20-poly1305@openssh.com": "chacha20", "aes256-gcm@openssh.com": "aes-256-gcm", @@ -15,12 +17,31 @@ const SSH_CIPHER_SSL_NAME: Partial> = { "3des-cbc": "des-ede3-cbc", }; -const availableCiphers = new Set(crypto.getCiphers()); +// Check if ssh2's native crypto binding is available (needed for chacha20-poly1305) +let ssh2BindingAvailable = false; +try { + require("ssh2/lib/protocol/crypto/build/Release/sshcrypto.node"); + ssh2BindingAvailable = true; +} catch { + try { + // ESM fallback: check if chacha20 works via OpenSSL createCipheriv + crypto.createCipheriv("chacha20", Buffer.alloc(32), Buffer.alloc(16)); + ssh2BindingAvailable = true; + } catch { + ssh2BindingAvailable = false; + } +} function filterCiphers(list: CipherAlgorithm[]): CipherAlgorithm[] { return list.filter((name) => { const sslName = SSH_CIPHER_SSL_NAME[name]; - return !sslName || availableCiphers.has(sslName); + if (!sslName) return true; + if (!availableCiphers.has(sslName)) return false; + // chacha20-poly1305 requires either native binding or working OpenSSL chacha20 + if (name === "chacha20-poly1305@openssh.com" && !ssh2BindingAvailable) { + return false; + } + return true; }); }