On 4/23/25 18:24, Theo Buehler wrote:
On Wed, Apr 23, 2025 at 05:11:18PM +0200, Theo Buehler wrote:
On Wed, Apr 23, 2025 at 12:35:51PM +0200, Andreas Bartelt wrote:
...
Another bit that will hurt is that ssh switched from aes-128-ctr to
aes-128-gcm by default last December:
https://github.com/openbsd/src/commit/08d45e79c0d607376dd5c42234e36d78473c3ae0
According to my tests, the default seems to be determined by the
preference from the client side as far as the Cipher is also supported
on the server side (i.e., like "ssl_prefer_server_ciphers off;" in
nginx's tls configuration semantics).
The most preferred symmetric cipher in the default config is actually
chacha20poly1...@openssh.com. Although this is correctly documented in
the corresponding man pages for ssh_config(5) and sshd_config(5), I
personally find the actual behavior based on the default
/etc/ssh/ssh_config and /etc/ssh/sshd_config configuration files rather
confusing, e.g.:
- default /etc/ssh/ssh_config contains this commented out line:
# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc
--> this looks to me like a more or less outdated and random example
which doesn't correspond to the actually used default config from the
man page. On the other hand, there are other commented out configuration
statements in default /etc/ssh/ssh_config such as
"#PasswordAuthentication yes" or "#UseDNS no" which correspond to the
actually configured behavior (i.e., the result would still be the same
with the # character removed). I personally would find it more
consistent to have the commented out defaults for Ciphers included in
default /etc/ssh/ssh_config and /etc/ssh/sshd_config (note that the
letter config file currently doesn't include an Ciphers statement at all).
This doesn't make much of a difference in the unaccelerated case:
Without AES-NI
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-128-gcm 174617.32k 211996.90k 693919.98k 754392.03k 775449.26k
aes-128-ctr 185805.70k 216658.12k 778577.33k 888563.84k 915544.45k
but, since our GCM ASM is pretty bad, this will hurt in the accelerated
case. jsing will be looking into improving that since this is also
important for TLS.
With AES-NI:
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-128-gcm 669421.74k 1886143.60k 3064423.66k 3495542.89k 3564934.49k
aes-128-ctr 990493.56k 3246635.81k 6959034.82k 9812672.93k 11506436.47k
I retested the large file scp transfer scenario with your patch:
scp with chacha20-poly1305: ~83 MB/s [previous result]
scp with aes-128-gcm: ~62 MB/s [previous result, without AES-NI]
scp with aes-128-gcm: ~219 MB/s [new result with your patch / AES-NI]
--> 350% improvement
scp with aes128-ctr/hmac-sha2-256-...@openssh.com: ~105 MB/s [new result
with your patch / AES-NI]
scp with aes128-ctr/umac...@openssh.com: ~215 MB/s [new result with your
patch / AES-NI]
--> aes-128-gcm with AES-NI is the fastest variant, at least on amd64.
At this point in time, I'd assume at least 95% of amd64 based CPUs,
which are active in the field, actually include AES-NI support. In order
to account for the overwhelming majority of users, it might be warranted
to remove chacha20-poly1305 from the top spot in the default
configuration(?). Or is the rationale to prioritize chacha20-poly1305
for all the (likely older) non-amd64 based CPUs which don't support any
specialized CPU instructions for aes-gcm?
While we could (and probably should) add OPENSSL_init_crypto() calls to
the various *add_all* API, I think a better first fix will be this,
which means that the cpuid_setup happens whenever a cipher or a digest
is invoked via EVP and the accelerated implementation should be chosen
if available:
And here's the diff including the *add_all* API, which are also needed
(otherwise the first call to cipher_init() will still end up using the
unaccelerated implementation).
Thanks a lot for looking into this and for your patch!
Index: crypto_init.c
===================================================================
RCS file: /cvs/src/lib/libcrypto/crypto_init.c,v
diff -u -p -r1.22 crypto_init.c
--- crypto_init.c 17 Oct 2024 14:27:57 -0000 1.22
+++ crypto_init.c 23 Apr 2025 12:27:08 -0000
@@ -99,18 +99,24 @@ LCRYPTO_ALIAS(OPENSSL_cleanup);
void
OpenSSL_add_all_ciphers(void)
{
+ /* Prayer and clean living lets you ignore errors, OpenSSL style. */
+ (void)OPENSSL_init_crypto(0, NULL);
}
LCRYPTO_ALIAS(OpenSSL_add_all_ciphers);
void
OpenSSL_add_all_digests(void)
{
+ /* Prayer and clean living lets you ignore errors, OpenSSL style. */
+ (void)OPENSSL_init_crypto(0, NULL);
}
LCRYPTO_ALIAS(OpenSSL_add_all_digests);
void
OPENSSL_add_all_algorithms_noconf(void)
{
+ /* Prayer and clean living lets you ignore errors, OpenSSL style. */
+ (void)OPENSSL_init_crypto(0, NULL);
}
LCRYPTO_ALIAS(OPENSSL_add_all_algorithms_noconf);
Index: evp/evp_cipher.c
===================================================================
RCS file: /cvs/src/lib/libcrypto/evp/evp_cipher.c,v
diff -u -p -r1.23 evp_cipher.c
--- evp/evp_cipher.c 10 Apr 2024 15:00:38 -0000 1.23
+++ evp/evp_cipher.c 23 Apr 2025 13:52:22 -0000
@@ -614,6 +614,9 @@ LCRYPTO_ALIAS(EVP_DecryptFinal_ex);
EVP_CIPHER_CTX *
EVP_CIPHER_CTX_new(void)
{
+ if (!OPENSSL_init_crypto(0, NULL))
+ return NULL;
+
return calloc(1, sizeof(EVP_CIPHER_CTX));
}
LCRYPTO_ALIAS(EVP_CIPHER_CTX_new);
Index: evp/evp_digest.c
===================================================================
RCS file: /cvs/src/lib/libcrypto/evp/evp_digest.c,v
diff -u -p -r1.14 evp_digest.c
--- evp/evp_digest.c 10 Apr 2024 15:00:38 -0000 1.14
+++ evp/evp_digest.c 23 Apr 2025 13:14:36 -0000
@@ -226,6 +226,9 @@ LCRYPTO_ALIAS(EVP_Digest);
EVP_MD_CTX *
EVP_MD_CTX_new(void)
{
+ if (!OPENSSL_init_crypto(0, NULL))
+ return NULL;
+
return calloc(1, sizeof(EVP_MD_CTX));
}
LCRYPTO_ALIAS(EVP_MD_CTX_new);