[Crypto] SSH protocol dissected, part V: toy SSH client with ECC in ~2k SLOC of Python

Previous blog posts: 1, 2, 3, 4.

This is a toy SSH client supports ECDH and ECDSA.

New KEX algos: diffie-hellman-group18-sha512, ecdh-sha2-nistp256, ecdh-sha2-nistp384, ecdh-sha2-nistp521.

New server/host algo: ecdsa-sha2-nistp256.

ECDH is used in place of DH and called 'ecdh-sha2-nistp256' - SHA2-256 will be used with it and NIST P-256 curve. So if KEX algorithm 'ecdh-sha2-nistp256' is picked, it will be used instead of DH.

I also added ECDSA support, which is used as a digital signature for DH or ECDH reply from server.

Thanks to cryptography.io module/library, these addition to my toyssh client were easy, as easy, as for the last version of my toytls client.

However, needless to say that TLS uses ASN1 encoding actively, as well as cryptography.io module. But in SSH protocol, ECDSA signature is transmitted as two bignums - r and s (as in DSA). (See calls to decode_dss_signature() and encode_dss_signature() functions -- these convert between ASN1 encoding and pair of bignums.)

ECDSA is like upgraded DSA, and despite DSA outdatedness, I added it to SSH nevertheless, just as a stepping stone towards ECDSA. It helped me. So I advise to learn DSA first, before ECDSA.

Also, you can login to server using ECDSA key. Generate it as: 'ssh-keygen -t ecdsa'.

Then copy-paste contents of id_ecdsa.pub file to $HOME/.ssh/authorized_keys file.

Then login: 'ssh user@host -i ~/tmp/id_ecdsa'. (Or add this info to $HOME/.ssh/config file.)

Toyssh can also login with such a key:

./toyssh_v5.py -h host -u user -pubkey id_ecdsa.pub -prikey id_ecdsa -server_host_algo ecdsa-sha2-nistp256

Here it is used instead of RSA.

Now a very important thing to understand: ECC cryptography is not mandatory to be used for both steps (KEX and signature).

Here is I use ECDH instead of DH, but (old) RSA signature:

toyssh_v5.py -h host -u user -pass pw -kex ecdh-sha2-nistp256 -server_host_algo rsa-sha2-256

And here I use (old) DH and ECDSA:

toyssh_v5.py -h host -u user -pass pw -kex diffie-hellman-group14-sha256 -server_host_algo ecdsa-sha2-nistp256

Usual openssh commands are:

ssh -v -oKexAlgorithms=diffie-hellman-group-exchange-sha256 -oHostkeyAlgorithms=ecdsa-sha2-nistp256 i@localhost

... and:

ssh -v -oKexAlgorithms=ecdh-sha2-nistp256 -oHostkeyAlgorithms=rsa-sha2-256 user@host

(But (open)SSH client will grumble about fingerprints saved/cached in '$HOME/.ssh/known_hosts' when switching between host key algorithms.)

Both RSA and ECDSA can sign DH or ECDH reply from server.

For that, almost all modern SSH servers supports at least three signature algorithms: RSA, ECDSA, ED25519. Run 'ls /etc/ssh' and you'll see private/public keys for all three algorithms -- they were generated during your Unix installation.

Bottom line: this toy SSH can connect to almost any modern SSH server, including those with disabled (outdated and/or old) RSA and DH algorithms.

Issues: 'keyboard-interactive' auth is not supported. (Required by SSH-2.0-OpenSSH_9.5 FreeBSD-20231004, for example.)

Download: ~2k SLOC of Python.

(the post first published at 20240529.)


List of my other blog posts.

Subscribe to my news feed,

Yes, I know about these lousy Disqus ads. Please use adblocker. I would consider to subscribe to 'pro' version of Disqus if the signal/noise ratio in comments would be good enough.