Asymmetric Encryption: How SSH Works
Luke, 14 Dec 2023
Introduction
Ive used SSH for years, but Ive never really spent the time getting to understand how it works, until today. I was once again going through the process of setting up a git client with a repository, using SSH keys for authentication, and was again wrestling with Sourcetree, which had again lost its SSH abilities, to my frustration. Time to really get to understand this, I decided .. so heres how it works.
Background
The proper name for the tech that underpins SSH (Secure Shell), is asymmetric encryption. Why asymmetric - because a mirrored process happens at each end of the communication.
The communication in question is between my git client, and the server that hosts it - whether in this case GitHub, or BitBucket, or another. I make a key pair locally, and i keep one half, and send the other half to github settings. But what is actually happening, and how do those keys get used? First, its important to understand what those public and private keys are. Grasping this bit is crucial.
Old fashioned encryption, like the type used centuries ago, used a cypher or code, that allowed the substitution of one letter for another. But for this to work, both ends of the communication needed the same cypher - and that part is the risky part, and it requires both ends to be in contact before the messages can be encoded at one end and decoded at the other. Asymmetric encryption is a clever way to prevent the need for the risky sharing of a cypher.
Key Pairs
In this modern method, the first part is the generation of not one but two mathematically linked keys, called a key pair. Whats clever is: either of these keys can be used to encode, and to decode. And both will encode, and decode the other. So, to be clear:
Key A (eg my secret key) can encrypt something, and Key B (the public part) can then decrypt it. And .. Key B (the public part)can encrypt something, and Key A(my private one) can then decrypt it. But .. If Im in possession of one of those keys, I cannot procedurally create the other. Its impossible.
To then set up asymmetric encryption, one of these keys is kept secret locally, and the other is made 'public' (or at least - its sent out into the world), for eg pasted onto my Github Settings page.
Importantly though - the other end does the same thing. So Github also creates a key pair - it has its own private key, and its own public key, which comes to me. I'll get into this later, but for now - back to the keys and how they work.
Why private and public? Two Important Benefits
First, so B (public) can decode something encoded with A (private). Nothing else can decode something encoded with A. So if something successfully decodes something using B, It has to have been made with A. And because A is privately held, It has to have been made by me. SO - this is a pretty foolproof way to ascertain that a message has come from only one place - the person who is in possession of that private key. I have been authenticated.
Second, if I encode something with someone else's public key, (dont forget, each key can both encode and decode), then only the person in possession of the other (private) part of that key pair can decode it again. So, I can encode something that only one other party can decode. Anyone can do this, but that doesnt matter (ultimately..).
So two things have been made possible: Ive been authenticated by another party, and Ive made a message that only that other party can decode. And all we have exchanged, is the public parts of our keys.
Now for the communication to fully work - I need both abilities. The other party needs to know that its me (authenticate me), and only they should have the ability to decode the message that they know is from me.
So heres the clever bit ..
Asymmetric encryption does both things at the same time
The total setup:
The complete picture is that : Ive made a key pair, and I keep one to myself, the secret (A) one, and send the other out into the world. But the other end does the same, so they have a secret (A) key of their own, and theyve sent me their public B key too. Both ends have their own private key, and the other parties public key. Two keys each.
These public keys are the only part that gets shared. So Ive not had to make secret contact with the other party. It doesnt matter if anyone else has seen these public keys.
When I send a message to the other party, the message is encoded with both A and B. It gets encoded with my private key, and it then gets encoded again, with the other parties public key.
At the other end, the decryption happens. The part thats been encoded with my private key, can be decoded by the public part of the key I shared. And the encryption that happened using the other parties public key, can be decoded by them with their own private part of that key.
In this way, both boxes are ticked: the source of the message (me) is certain, and the message is only decodable by the other party. The same thing happens when I get communication back: the other party encodes with both my public key and their own private key, and I can be sure at my end of who its from, and that its secret, because both decodes work.
Now back to Sourcetree, which seems to lose links to keys whenever it feels like it. Heres a quick tip for that: Sourcetree requires that the key you generate locally has a particular name. So even though the terminal process of creating the key says you can name it anything, in the case of Sourcetree, you cant: the public / private keys must be given the filename: