How a Safety Code Proves You Are Connected to the Right Device

By ShareDrop.org Engineering · Published · Updated

After a ShareDrop.org connection is established, both screens show a six-digit code. If you read them out and they match, something cryptographically meaningful has been proven: no third party sits between your devices. Here is why that works, and why “encrypted” alone would not be enough.

Encrypted to whom?

WebRTC encrypts every connection (details), but encryption only guarantees privacy with whoever is on the other end. The residual risk is a machine-in-the-middle: an attacker controlling the signaling path could try to establish one encrypted connection with the sender and another with the receiver, decrypting and re-encrypting in between. Both victims see a padlock; neither sees each other.

Fingerprints, and a code built from them

Every WebRTC endpoint has a session certificate whose fingerprint (a hash) is exchanged during negotiation and enforced by the DTLS handshake. The crucial observation: in an attacked connection, each victim negotiates with the attacker's certificate, so the fingerprint pairs on the two sides differ. A safety code exploits this asymmetry:

code = SHA-256( context ‖ sorted(fingerprint_local, fingerprint_remote) ‖ session-id )

Why comparing must happen outside the app

If the app showed you “the other side's code” over the same possibly compromised connection, the attacker would simply relay codes. The comparison only has value over an independent channel: reading it aloud in person, over a phone call, or any medium the attacker does not control. This is the same reasoning behind Signal's safety numbers — the human is the out-of-band channel.

How ShareDrop.org presents it

What safety codes do not do

A matching code proves the endpoints hold the keys: it does not prove the person at the other endpoint is who you think, and it says nothing about what they do with the file after arrival. It closes the network-level gap; human trust remains yours to establish.

Where the six digits come from

Each browser generates its own certificate for the session and announces the certificate's SHA-256 fingerprint during setup — the a=fingerprint line in the session description. Once connected, each side holds two fingerprints: its own, and the one it received for the peer. The safety code is derived from both:

  1. Take the two fingerprints and put them in a fixed order (sorted), so both devices start from the same input regardless of who is sender and who is receiver.
  2. Hash the combined string with SHA-256.
  3. Take enough of the result to produce six decimal digits.

Both devices do this independently, without exchanging anything further. If both hold the same pair of fingerprints (which is the case when they are genuinely connected to each other), they compute the same six digits. If an attacker sits in the middle, there are two sessions: your browser holds your fingerprint and the attacker's, the peer's browser holds the peer's and the attacker's. Different inputs, different codes. The attacker cannot fix this, because they cannot make their certificate's fingerprint equal yours.

How strong are six digits?

There are a million possible codes. An attacker who has substituted themselves into a session cannot choose the code the two victims will see; they get whatever the maths produces, and it matches the legitimate code with probability one in a million. They get exactly one attempt per session, because a failed comparison ends the session and the next one has fresh certificates. One in a million, once, checked by a human in real time, is more than enough.

Messaging apps show much longer codes (Signal's safety numbers are sixty digits), because they verify something different: a long-term identity that must stay valid across months of messages and can be attacked offline at leisure. A per-session code compared live has none of that exposure, which is why it can be short enough to read aloud.

Comparing the code in practice

What a mismatch actually means

Three things can produce different codes, in decreasing order of likelihood:

  1. The connection was rebuilt. A network change or a dropped link means new certificates on reconnect, which means a new code on both sides. If the two screens now agree with each other on the new code, that is what happened.
  2. You are looking at different sessions. One person is still on an old screen, or connected to a different room. Both start again from a fresh invite.
  3. Someone is in the middle. Both sides on fresh sessions, both comparing current screens, codes still differ. End the session, do not send the file, and re-invite through a channel you trust — ideally a different network.

The order matters: reconnects are routine, and a tool that raised an alarm on every one would train people to ignore it. ShareDrop.org resets the verified state and shows the new code without drama, and leaves the judgement to the two people who can actually see both screens.

Why the app does not verify this for you

Automatic verification needs something to verify against: a stored key for the other person, which needs an identity, which needs an account. ShareDrop.org has none of those on purpose, so there is nothing to pin the peer's certificate to — every session is between two strangers as far as the protocol is concerned. The safety code replaces the missing identity with the one thing two people always have: the ability to look at each other's screen. It is a deliberate trade (no accounts, one small manual step for the transfers that warrant it), and for most transfers between people who know each other, the step takes five seconds.

The same idea elsewhere

SystemWhat you compareWhat it verifies
Signal safety number60 digits or a QR code, per contactA long-term identity key, once, valid for all future messages
WhatsApp security code60 digits or QR, per chatSame design as Signal
SSH host key fingerprintA hash shown on first connectionThe server's identity, pinned thereafter
ShareDrop.org safety codeSix digits, per sessionThat this session's two keys belong to these two devices

The pattern is the same everywhere: cryptography establishes a secure channel to someone, and a short human comparison establishes that the someone is who you meant. The length of the code follows from how long it must stay valid and whether it can be attacked offline, which is why a per-session code compared live can be six digits and a per-contact key for years of messages is sixty.

How this is tested

The protocol test suite plays the attacker: it substitutes one side's DTLS certificate fingerprint during connection setup (exactly what a man-in-the-middle relaying two separate encrypted sessions would produce) and asserts that the two devices now derive different safety codes. A matching code with substituted fingerprints would be a broken build; the suite makes that state unshippable. The codes are derived from both endpoints' certificate fingerprints, so neither side can compute the code alone.

Standards referenced