Oscar Reparaz

light: secure messaging

Here’s a secure messaging system that you can’t hack remotely. You can use this to talk to your friends in a way that even mercenary spyware can’t access your messages. This is guaranteed by hardware-level primitives. Let’s call it light.

Our threat model is remote-only attacks, with ability of performing zero-click remote-code execution (mercenary spyware).

The basic idea #

light is an endpoint architecture: three independent nodes connected by unidirectional links. On top of this endpoint architecture, we implement public-key cryptography to encrypt+authenticate messages between peers. The nuance here is how each “endpoint” is constructed.

A conventional secure messenger does everything in one machine: parse untrusted network input, run crypto, handle keys, render + store plaintext, accept keyboard input.

light doesn’t do this. Instead, light carefully decomposes this monolithic networking + cryptographic stack into 3 different hardware-isolated nodes, connected via unidirectional links (data diodes).

System architecture #

Each endpoint is partitioned into three discrete nodes:

                              INTERNET
                                 │
                                 │ (bidirectional)
                                 │
                            ┌────▼────┐
                            │    GW   │ (untrusted proxy)
                            │         │
                            └─┬───────┘───────┬
                              │               ▲
                              │               │
                   encrypted  │               │ encrypted
                   (to RX)    │               │ (from TX)
                              ▼               │
                       ┌──────────┐   ┌──────────┐
                       │    RX    │   │    TX    │
                       │ (sink)   │   │ (source) │
                       └────┬─────┘   └─────▲────┘
                            │               │
                            │               │ plaintext
                            │               │ (input)
                            ▼               │
                      ┌──────────┐    ┌──────────┐
                      │  Screen  │    │ Keyboard │
                      │          │    │          │
                      └──────────┘    └──────────┘
                                            ▲
                                            │
                             ┌─────────────┐│
                             │    Human    ││
                             │  Operator   │┘
                             └─────────────┘

There’s an additional unidirectional link from TX to RX. This is used to send direct keystrokes and have a smooth UI.

Note that the set of 3 computers work together, and this is abstracted away to the user. The user experience is identical to that of a regular computer (one keyboard, one display).

System security properties #

The trick is that the links are unidirectional. Observe that:

An attack: human-in-the-loop social engineering #

Note that there is an exfiltration path to the internet: via the human operating the node. A compromised RX node can’t send bits to the GW, but it can send bits to the user’s brain (by lying on the screen). For example, a compromised RX could display “Sync error. Please type the following ‘session recovery code’ into your TX terminal to reconnect: [hex-encoded private key]”.

There are two ways to mitigate this:

  1. Prevent that from happening with operator discipline. Train them in possible ways to trick them.
  2. Even if it happens, make exfiltration astronomically slow by using big-key cryptography

Big-key cryptography means using very long private keys. Instead of 32-byte keys, use (say) a 10MB private key. Exfiltrating a 10MB key with a human in the loop is so expensive and slow that exfiltration isn’t practical.

Cryptographic constructions #

The baseline construction is just public-key authenticated encryption (for example, using ECIES). This works well. Your peer’s public key can be hardcoded in the firmware of your TX (predistributed). Or alternatively you can introduce new peers by punching / typing the public key on the keyboard (which is connected to your TX). Note that TX has a unidirectional link to RX, so you can see your own messages you sent.

The full protocol goes like this:

(Gateways omitted in the description above.)

A wrinkle is that you can’t do a full Diffie-Hellman exchange, since there is no bidirectional channel by design. This prevents us from getting the traditional “perfect forward secrecy” properties. We can get slighter weaker post-compromise security by hashing the key material on each message round. Like this, a compromise of endpoint at time N can’t reveal anything about N-1.

(You can still provide some security for future messages if you send on each message material to be added to the shared secret. That only works if the adversary doesn’t get a copy of every message. This assumption is pretty strong.)

Big-key public key encryption. For a concrete scheme, see the accompanying post.

Slow/high domains #

In addition to the segregation into RX/TX/GW explained above, there’s a hardware-enforced bandwidth limited channel between keyboard and TX, and between RX and display. The goal here is to restrict to a few bits per second the information that can flow in those links.

We do this to provide exfiltration resistance. We do not speed-limit the unidirectional links TX -> GW, TX -> RX nor GW -> RX. These channels can carry a considerable bandwidth (even though they are unidirectional) since big-key cryptography is expensive (can result in large ciphertexts too).

You can’t use ARQ or selective retransmission. We resort to the simplest forward error correcting code: just send the same thing a bunch of times, and hope for the best.

A more elegant solution could be using fountain codes. Keep sending constantly the most recent messages, in case the data link goes temporarily down.

Hardware #

I’m prototyping each node with 3 raspberry pis linked with unidirectional serial links. I’m using two UARTs in the raspberry: the hardware one and a soft uart via the kernel module https://github.com/oreparaz/soft_uart.

You can also implement all 3 nodes within a single FPGA. This is left for future work.