Key Exchange Methods in Ren-C

Having given a summary of Checksums and Secure Hashes, I thought I'd follow up with a quick description of something you're likely not as familiar with: Key Exchanges.

There's old quote I like (but can't find a source for):

"The shared secret is capital. We may spend it or squander it."

An example of taking advantage of a shared secret is when people want to share an encrypted .ZIP file. If you and your friend both know the encryption password that no one else knows...then you could put the file on a public server for your friend to download. If you trust the encryption, the fact it was public would not matter.

But what if the situation is that your friend has a password that only they know... and you have a password that only you know? That wouldn't seem to help with the .ZIP file scenario, because it expects the same password to decrypt as was used to encrypt it.

Key Exchange is a way of taking your individual "passwords" and coming to an agreement on a third "password" that only the two of you know. Amazingly enough, you can carry out the conversation where you establish the shared password in public.

Creating one Shared Secret from two Non-Shared Secrets

For educational purposes, people use paint-mixing as an analogy for key exchange. It's really "multiplying big prime numbers" instead of mixing paint, but it's visual and easy to see.

This assumes everyone in the world has some kind of weird "common paint". This paint isn't white (because if you mixed it with something that would be too easy to guess at the precise shade you had mixed it with). And it isn't black (because mixing might just get you something too dark to measure well).

But the key point to absorb is what the diagram says: we assume that mixture separation is expensive. Once you've mixed the common paint with your secret color, it produces a new shade that no one else knows how to make exactly.

When you and your friend exchange your mixtures you cleverly go to your private lairs and each add your secret color to the other's mixture. Now both of you have the same weird color, and this is a secret you share.

Ren-C Supports Diffie-Hellman Key Exchange

I oversimplified this by saying you each start with a "password"...because that made it sound like you could just pick a phrase out of your head. In reality, choosing your secret involves some tricky math...to make sure your secret paint color is a good secret paint color. You don't pick these--you ask the computer to generate it.

To get the ball rolling, you need to specify what kind of "common paint" to use. You make that by picking two suitable prime numbers, a modulus and a base. Then you can ask for a unique random secret to be generated.

For the sake of education, I've made it possible to use relatively bad paint mixes with the /INSECURE refinement. It won't allow numbers that are so broken the process won't work (for instance: non-primes, or primes that don't meet the basic requirements of the algorithm). This lets you work with small enough numbers that you can see for yourself what's going on more easily.

So let's use a modulus of 9 and a base of 3:

>> mine: dh-generate-keypair/insecure #{09} #{05}
== make object! [
    modulus: #{09}
    generator: #{05}
    private-key: #{07}
    public-key: #{05}
]

>> theirs: dh-generate-keypair/insecure #{09} #{05}
== make object! [
    modulus: #{09}
    generator: #{05}
    private-key: #{05}
    public-key: #{02}
]

So privately, my secret is 7... and their secret is 5. But we want to come to an agreement on a new number while only sharing with the public my "mixture" of 5 and their mixture of 2.

>> my-shared: dh-compute-secret mine theirs.public-key
== #{02}

>> their-shared: dh-compute-secret theirs mine.public-key
== #{02}

So here you see each of us could come to a common agreement of 2. You can follow through the math on the Wikipedia page if you want...but it's enough to know that it works.

What makes for a good (big!) modulus and base to use? You don't really need to come up with them yourself, although there are algorithms for it. There are papers that publish some good choices--and we should probably provide a way to default to well-known ones, like maybe accept either an object or an ISSUE!

>> dh-generate-keypair #RFC-3526
; ...or...
>> dh-generate-keypair make object [base: ..., modulus: ...]

But the main thing to know is that both sides have to agree on the "common paint" to use, in order to come to the same conclusion. So dh-compute-secret won't work unless the same numbers were used here.

We Also Support Elliptic Curve Key Exchange (ECHDE)

Modern Internet Transport Security has moved on from traditional Diffie Hellman to trickier math. But the premise is the same.

In the interface, we only support two "common paints" for this method: "secp256r1" and "curve25519". There's no option for small answers here:

>> mine: ecc-generate-keypair 'curve25519
== make object! [
    public-key: make object! [
        x: #{121413C34DC265025F24CBEBBA6065B9
             75F1BFA6E493D07A0F4776FAE03DC245}
        y: #{00000000000000000000000000000000
             00000000000000000000000000000000}
    ]
    private-key: #{610A8D99A72500B3A2E8A1FD714FA412
                   17F0A0EA5EDFC9CFBDAE0425E199DC70}
]

>> theirs: ecc-generate-keypair 'curve25519
== make object! [
    public-key: make object! [
        x: #{10D65366D8C9229591C99903D3B5EB0F
             57709AD27E37989E4782050D2B9B2B93}
        y: #{00000000000000000000000000000000
             00000000000000000000000000000000}
    ]
    private-key: #{7C3262BF6028B049EEDC6C37E37A8261
                   EA4DF31F16E4D534D92A7EF11D974618}
]

But it works the same way; you come to the same conclusion when combining your partner's public portion with your private portion:

>> my-secret: (
    ecdh-shared-secret 'curve25519 mine.private-key theirs.public-key
)
== #{E27891074A60250580B8F2C7CB2448A9AA491C97161D7C8D381348D90E438025}

>> their-secret: (
    ecdh-shared-secret 'curve25519 mine.private-key theirs.public-key
)
== #{E27891074A60250580B8F2C7CB2448A9AA491C97161D7C8D381348D90E438025}

>> my-secret = their-secret
== #[true]

Would Average Users Ever Need Key Exchange Functions?

Right now, the main reason most people would care whether the language has these key exchanges is because without them you can't do TLS. So no reading or writing over HTTPS.

You really only need key exchanges when protocols are trying to establish private channels of communication. So notably, some cryptographic protocols (like Bitcoin) don't need key exchanges...because they're carrying out their work in public.

  • It would be neat if we could democratize the creation of cryptographic protocols. I think giving people easier and more transparent access to these kinds of things could foster some grassroots innovation, where people would build exactly the security they needed into a program's design...no more and no less.

    • This would stand in contrast to today's methods, where "security" is accomplished by standing on top of a mountain of protocols (using a literal zoo of cryptographic algorithms) to tunnel and log in somewhere that they are "safe"...and putting more data than they need to in that place.
  • But even "simple" cryptography is tricky to reason about, and people are lazy. I myself am pretty guilty of doing things like falling back on my GitHub password and resetting my keys instead of doing a good job of filing them in safe places.

    • Convincing people their programs should be "organic and locally sourced"... by tailor-making the protocols and asking their users to keep track of files, is going to be a hard sell to those who are happy to use OAuth and leave this all up to Google.

So pessimistically speaking, I don't know that we're going to be able to market easy-to-use key exchange to anyone as a killer feature. It's a nice thought, and I certainly like having it available to tinker with. But I'd be surprised if anyone reading this has an idea how to use it in something they're working on.

2 Likes