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);

Reply via email to