I got interested in Keybase.io the day I left Google in March, and I’ve been evangelizing it, but even more the idea behind it: Using authenticated posts here and there to prove public-key ownership. Also I’ve contributed Keybase-client code to OpenKeychain (let’s just say “OKC”), a pretty good Android crypto app. I’m more or less done now.

This report is too long, and will probably be of interest only to the twelve people in the world who care about crypto implementations, key discovery, and modern Android apps.

What it does · There are now three screencasts over on YouTube: Sending a message, Receiving a message, and Can I trust this key?

The last of these is new, and illustrates the interesting part of the project: Showing cloud-based trust evidence from Keybase, then independently replicating the Keybase “proofs”. The great thing about a Keybase-style key directory is that you can use it without trusting it, as OKC demonstrates.

Status · My code is stable and seems to work; OKC’s lead developers Dominik and Vincent think OKC is getting feature-complete and got tired of my pull-request flurries, so they gave me commit access. I had to dig deep into my limited git-fu, but now you should be able to clone and build from this branch. An official Google-Play-Store release will follow at some reasonable point after that. I have no major itches left unscratched on this project for the moment.

The big changes needed to make OKC more generally usable by non-geeks need to come from platform builders, chiefly Google, who should fix Gmail already, it’s easy to recognize OpenPGP messages and there’s never any point in showing the encrypted form to a human being.

In theory, my KeybaseLib library should be maximally usable by anyone. And I think it is, except for it’s got an Android dependency on … wait for it … Base64. Which I could work around with dependency-injection machinery I suppose. Except for, that would be ridiculous.

The license is currently GPL2, which I think appropriate for crypto infrastructure, but I could probably be persuaded to do Apache if anyone needed it.

Is it useful? · I’m not currently in any relationships that I feel require encrypted communication, so it’s not actually useful for me right now. If I were, I’d be using the How To Be Secret technique, and OpenKeychain would be essential.

Git/GitHub notes · Boy, has GitHub ever become a single point of failure. And the fact that it’s VC-fueled makes it immensely more fragile; a risk factor for the whole open-source ecosystem. But hey, it works great, the irritants are too small to mention.

And as for Git itself; all these years later, I’m really still dubious. Is it even possible to have a tool that does all the things serious OSS projects need and runs at blinding speed; but without the correspondingly-blinding complexity? One of my more popular tweets reads: “I confess: I sometimes type git commands I don’t understand, when I’m told they’ll make a git problem I don’t understand go away.”

I find the Java language and its sprawling libraries, plus the immense landscape of the Android Application framework, much easier to understand than the thing we use to manage source code; something feels wrong about that.

Among the git things I don’t understand, submodules are right up there.

Modern Android apps · Speaking of the Android framework substrate, wow; Is there ever a lot of there there. OKC uses a big swathe of it, mostly by the book; but a quick trawl through the codebase turns up 11 workarounds marked by references to StackOverflow questions (8 unique).

I remember when fragments were new and confusing, but it all seems pretty elementary now; your Activity does the chrome around your vertical/horizontal/big/small layouts, and then you drop in the fragments and they do the actual interaction.

OKC talks to the network and does compute-intense crypto and has a lot of different screens and menus and options, but still manages to be pretty idiot-proof. I learned quite a bit about Android-app building from it. I think Dominik and Vincent and the others who contributed should be proud; I’d call it a good example of a well-done modern Android app.

Displaying text · Keybase evidence in OKC presents as chatty narratives with tappable links to the “proofs” and their verifications. Since it looks kinda hypertext-y, I used a WebView. The other OKC guys were all Ewwwwww… WebView bad! This is supposed to be highly secure crypto code! Well, OK. So now it’s all made from little Android text spans courtesy of SpannableStringBuilder. This is something I’d never done before; a little klunky but not that painful. It’s perfectly reasonable to worry about a WebView getting out of control.

Talking to a Prover · KeybaseLib’s API is a little strange. The search part is straightforward; you can search Keybase for any old string and get a bunch of Match objects back, or you can fetch a User by username or key fingerprint; from a User you can get a list of Proof objects.

Before I go on I should explain that I was building not only KeybaseLib but also the OKC code that would call it; so I was my own customer.

Suppose you want to verify a proof. It gets weird, because verifying a proof requires doing a bunch of crypto, as well as oddities such as fetching DNS TXT records. In an ideal world you’d like library methods to be one-shot and self-contained:

if (proof.verify()) { alert("Yay!"); }

To do a call like that I’d have to embed a DNS fetcher and an OpenPGP implementation in the library. Which I wouldn’t of course; I’d rely on other libraries. Which means that a caller wanting to use KeybaseLib would have to take dependencies on those. Which would never happen, because people who use this sort of code have nasty suspicious minds and would be all “You want me to believe that proof because you said that your DNS library and your crypto library said everything was A-OK? Uh-huh!”

The conclusion is that KeybaseLib should rely on its caller to do a few things, the most important being OpenPGP signature checks. The natural implementation falls out: Pass KeybaseLib an interface with callbacks to verify signatures and so on.

Except for, I ended up not liking that either. OKC likes to display progress bars and pass control back and forth between the UI thread, AsyncTask background threads, and its own pet Service. I totally couldn’t figure out how to do a one-call verify() method and make things easy.

So the current implementation has a Prover class, but the caller micromanages it rather than vice versa. As caller, you tell it to fetch the proofs, then you ask it for the PGP message so you verify the signature, then you ask it if it needs to fetch a DNS record, then finally you ask it if it needs to look at the raw message bytes. Which lends itself nicely to a host app like OKC; but has a bit of a code smell. The real question is whether OKC is a typical customer, or an anomaly.

Talking to crypto · I’m really only interested in crypto for person-to-person messaging and at the moment that mostly means OpenPGP (even though things like miniLock are interesting). Yeah, while OpenPGP keys and messages are fatter than entirely necessary, the software is ubiquitous and I have to say the interoperability is totally top-notch. I was working with keys and messages generated by lots of different software and I never had an interop hiccup. I hear about a few, but they tend to hit hard-core crypto hackers who do weird shit with subkeys; or veterans working with old keys produced by old software.

I think I’ve said this before, but RFC 4880 is really just fine; when I’ve needed to look something up, it was easy to find and easy to understand.

The problem I’ve seen with crypto libraries in general and the BouncyCastle/SpongyCastle suite in particular is that they try to Solve The Whole Problem. All I care about is decrypting, encrypting, and signature-checking OpenPGP messages with asymmetric keys and I’d like to have exactly three API calls to do those three things. But that wouldn’t Solve The Whole Problem, would it? So you have to work a lot harder to do those basics in Java.

What a Keybase.io proof actually is · There’s the long form and the short form. The long form is (pardon the RFC4880 jargon):

  1. An ASCII-armored message,

  2. which contains a Compressed Data packet (tag=8),

  3. which contains a One-pass Signature packet (tag=4) identifying the key it’s signed with,

  4. followed by a Literal Data packet (tag=11),

  5. and a signature packet (tag=2).

I don’t know how they construct them, but gpg --decrypt can unpack them just fine. The kind of logic you need to pick them apart isn’t hard once you figure out what’s going on; see the verifySignedLiteralData() method in PgpDecryptVerify.

The second form is a sort of signature computed over the message that’s short enough to fit into a tweet or DNS TXT record. It’s a Web-safe base64 of a prefix of the SHA-256 digest of the binary bits in the encrypted form of the message. Once you’ve stripped the ASCII, the code’s pretty straightforward; see checkRawMessageBytes().

Being paranoid · All the Keybase “proofs” rely on posting a signed message (one of the two formats I just listed) in a in a way that can be linked to a well-known identity like Twitter or a domain name or a Reddit account or whatever. The variations aren’t dramatic but they’re kind of fun; the code’s all in com.textuality.keybase.lib.prover.

Each of them has a comment headed “Paranoid Interlude” introducing the section where it tries to convince itself that the proof is believable. Here’s the summary:

  • For Coinbase: Pretty easy, the desired Coinbase handle has to be in the path to the proof doc, and we want to make sure the data came from coinbase.com, not some stealthy redirect.

  • For DNS: Not much scope for paranoia here; if a TXT-record segment for the claimed domain name has the sig, you’re good.

  • For GitHub: There’s a special API URL you can fetch a plain-text version of the gist from, so you need to be sure that the handle they’re claiming is in the path to it (case-insensitively, sigh), and that it’s actually coming from a GitHub property, either github.com or githubusercontent.com.

  • For Hacker News: The handle being claimed has to appear in the query part of the post URL in a name/value pair with id=, and the data has to be coming from ycombinator.com.

  • For Reddit: It gets tricky, since the proof’s URL just looks like /r/KeybaseProofs/some-gibberish and the JSON you get from it is pretty gnarly; so you have to plumb into it to verify that the sig is in the title and the claimed handle is the value of the author property.

  • For Twitter: It’s probably the hardest. First, using Twitter’s REST API in an open-source app is essentially impossible, so you have to do HTML scraping. Second, you have to worry about someone’s @-reply to a proof tweet containing the sig. So I brute-force extract the tweet’s HTML head and make sure the sig is in the title. We all know the chthonic horrors that can be unleashed by trying to parse HTML naively, but this feels pretty safe.

  • For a Web Site: It’s pretty simple, just retrieve the proof and make sure it came from there, even after redirects.

OpenPGP futures · “Never re-implement crypto code!” they always say, and I think they’re usually right. But boy, would the Java and Android ecosystems ever benefit from a crypto library that doesn’t Solve The Whole Problem, but just does OpenPGP messaging and that’s all. If I were a young hotshot with a few cycles, I’d be thinking seriously about taking that task on.

Thanks! · To Dominik and Vincent from OKC, and Max and Chris from Keybase. I’ve learned an enormous amount and had fun doing it, and those guys are all ace.



Contributions

Comment feed for ongoing:Comments feed

From: Janne (Nov 19 2014, at 23:01)

Gitorius is a good alternative, should Github fail badly. Better, it's based in Norway and owned by a Polish company, so it has a different exposure profile against any regulatory issues as well.

[link]

From: Leonardo Herrera (Nov 20 2014, at 08:08)

You had me at "chtonic".

[link]

From: Brian Slesinsky (Nov 20 2014, at 22:16)

Sounds neat!

I must be misunderstanding something about the Base64 dependency. Surely it can't be too hard to reimplement it?

[link]

From: Miroslaw Baran (Nov 21 2014, at 02:56)

…re: github monoculture; fortunately there are alternatives, gitorious being one, bitbucket being another, and you can always host your own repositories if you're so inclined.

[link]

From: Aaron (Nov 21 2014, at 20:31)

"I find the Java language and its sprawling libraries, plus the immense landscape of the Android Application framework, much easier to understand than the thing we use to manage source code; something feels wrong about that."

Amen.

Kids like playing with their tools.

[link]

From: Alan Griffith (Nov 22 2014, at 08:19)

For "just does OpenPGP messaging and that’s all" couldn't gnupg be forked and all the extra stuff be taken out?

[link]

author · Dad
colophon · rights
picture of the day
November 19, 2014
· Technology (90 fragments)
· · Android (64 more)
· · Java (123 more)
· · Security (39 more)

By .

The opinions expressed here
are my own, and no other party
necessarily agrees with them.

A full disclosure of my
professional interests is
on the author page.

I’m on Mastodon!