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.
In order to login, SSH client seeks for key in $HOME/.ssh/config file. If found, it will try to use it.
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.
If you want to muscle your cryptographical abilities, try to use this toy SSH client with '--no-encryption' option and see if you can collect enough information to break into SSH server after eavesdropping.
MITM attack is still possible, but server's fingerprint would be different, as in case of MITM with password-based auth.
But... Losing a key pair from your client computer is worse. Attacker can just use it. Password-based auth looks better in that sense -- you keep it in your mind. On the other hand, key pairs can be protected by password as well: ssh-keygen utility offers this. And then password will be asked each time you try to use this key.
Also, as you can see now, the same key pair can be used for several hosts. Why not? This is OK, but keep in mind that losing one pair can compromise security of all other hosts with the same key.
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.
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.