ssh: allocate name lists in one piece when unmarshaling

parseNameList split a comma-separated name list with bytes.Split and
then converted each part to a string, allocating the [][]byte from
Split and a separate string for every name. A kexinit message has ten
name lists. For example, the one sent by the OpenSSH 10.3 client holds
68 names in 1594 bytes.

Instead, convert the list to a string once and split that with
strings.Split. The client already does for the server-sig-algs
extension, so a name list takes two allocations no matter how many
names it has.

The names are now substrings of the list they came from. findCommon
returned the agreed name from the client's list, which on a server is
the peer's, and the negotiated algorithms are kept for the lifetime of
the connection. They would have kept the peer's key exchange, host
key, cipher and compression lists alive. This is over 1 KB per
connection for an OpenSSH client. Return the name from a local list
instead, so that nothing from the peer's kexinit outlives the key
exchange.

goos: darwin
goarch: arm64
pkg: golang.org/x/crypto/ssh
cpu: Apple M1 Max
                         │  base.txt   │               new.txt                │
                         │   sec/op    │    sec/op     vs base                │
UnmarshalKexInitMsg-10     3.809µ ± 2%   2.383µ ± 11%  -37.44% (p=0.001 n=20)

                         │   base.txt   │                new.txt                 │
                         │     B/op     │     B/op      vs base                  │
UnmarshalKexInitMsg-10     5.188Ki ± 0%   2.789Ki ± 0%  -46.23% (p=0.000 n=20)

                         │  base.txt  │              new.txt               │
                         │ allocs/op  │ allocs/op   vs base                │
UnmarshalKexInitMsg-10     126.00 ± 0%   30.00 ± 0%  -76.19% (p=0.000 n=20)

The other benchmarks in the package are unchanged.

Fixes golang/go#82099

Change-Id: Id75e931af48632ffb2a107cbd8a6fd622c29f93e
GitHub-Last-Rev: 271b8ad174aca8dc5b59ba3044d0cc882161d2fe
GitHub-Pull-Request: golang/crypto#377
Reviewed-on: https://go-review.googlesource.com/c/crypto/+/848045
Reviewed-by: Nicola Murino <nicola.murino@gmail.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: David Chase <drchase@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
2 files changed
tree: 6cb2bc43600fdb97c565c8ab51c83d0814a7e46d
  1. acme/
  2. argon2/
  3. bcrypt/
  4. blake2b/
  5. blake2s/
  6. blowfish/
  7. bn256/
  8. cast5/
  9. chacha20/
  10. chacha20poly1305/
  11. cryptobyte/
  12. curve25519/
  13. ed25519/
  14. hkdf/
  15. internal/
  16. md4/
  17. nacl/
  18. ocsp/
  19. otr/
  20. pbkdf2/
  21. pkcs12/
  22. poly1305/
  23. ripemd160/
  24. salsa20/
  25. scrypt/
  26. sha3/
  27. ssh/
  28. tea/
  29. twofish/
  30. x509roots/
  31. xtea/
  32. xts/
  33. .gitattributes
  34. .gitignore
  35. codereview.cfg
  36. CONTRIBUTING.md
  37. go.mod
  38. go.sum
  39. LICENSE
  40. PATENTS
  41. README.md
README.md

Go Cryptography

Go Reference

This repository holds supplementary Go cryptography packages.

Report Issues / Send Patches

This repository uses Gerrit for code changes. To learn how to submit changes to this repository, see https://go.dev/doc/contribute.

The git repository is https://go.googlesource.com/crypto.

The main issue tracker for the crypto repository is located at https://go.dev/issues. Prefix your issue with “x/crypto:” in the subject line, so it is easy to find.

Note that contributions to the cryptography package receive additional scrutiny due to their sensitive nature. Patches may take longer than normal to receive feedback.