[Crypto] SSH protocol dissected, part III: publickey auth

Previous parts: 1, 2.

Two most popular auth methods in SSH are password-based and publickey. Let's see how the second works.

On a client's side I generated RSA key pair using ssh-keygen. Then I uploaded newly generated public key to server using ssh-copy-id. In fact, the ssh-copy-id utility is a porcelain-kind utility (in terms of git). All it does is copy your public key to server's $HOME/.ssh/authorized_keys file. You can do the same using your favorite text editor while logged to server via SSH (this is why ssh-copy-id requires password to login to server for the first time).

When SSH client sends 'ssh-connection' with 'publickey', SSH server checks the $HOME/.ssh/authorized_keys file for that user. If it's absent, authentification can't go any further.

Client sends his publickey. Server compares it to what is in $HOME/.ssh/authorized_keys. If it's the same, we can proceed further. If not - not.

Now a client constructs another hodgepodge, that contains:

The most important part of this hodgepodge is H. The whole blob is signed by client's private key and the signature is sent to server. The server checks signature using client's public key from $HOME/.ssh/authorized_keys.

And this is why you hear that publickey auth is more secure than password-based. If an attacker can decrypt all the packets, it can see plain password. But here she/he can't do anything. Both public keys are of no use. H value is different at each connection, so replay attack isn't possible.

Attacker must use client's private key to login. No other options for attacker exist.

I added all this to my toy SSH client. Now ~1250 SLOC.

./toyssh_v3.py -h HOST -u i -pubkey /home/i/.ssh/id_rsa_HOST.pub -prikey /home/i/.ssh/id_rsa_HOST

This time I use a well-known cryptography library. It can parse SSH private key and sign a blob with this key. This is what I used in my toy SSH client.

Official info about publickey auth: 1, 2, 3.

Download latest version.


A word about AES-CTR. As I wrote before, SSH use it in SDCTR mode (stateful-decryption CTR mode). In other words, counter is global. Why? Otherwise two similar packets would produce the same ciphertexts. This may be undesirable. Attacker will know that clients sends the same commands or server responds with similar replies. Some cryptographers compare this with the well-known joke about ECB and Linux penguin.

The same story about incorporating packet number into HMAC when calculating MAC for each packet. MAC must be different for each packet, even if packets are the same.

(the post first published at 20220917.)


List of my other blog posts.

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.