view all posts by Tim Bray

Keybase Client

Tim Bray Posted by Tim Bray | Wed, 19 Nov 2014
see the original posting from ongoing

I got interested in Keybase.io the day I left Google in March, and Ive been evangelizing it, but even more the idea behind it: Using authenticated posts here and there to prove public-key ownership. Also Ive contributed Keybase-client code to OpenKeychain (lets just say OKC), a pretty good Android crypto app. Im 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; OKCs 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, its easy to recognize OpenPGP messages and theres 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 its 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?

Im not currently in any relationships that I feel require encrypted communication, so its not actually useful for me right now. If I were, Id 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 its 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, Im 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 dont understand, when Im told theyll make a git problem I dont 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 dont 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; Id 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 its all made from little Android text spans courtesy of SpannableStringBuilder. This is something Id never done before; a little klunky but not that painful. Its perfectly reasonable to worry about a WebView getting out of control.

Talking to a Prover

KeybaseLibs 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 youd like library methods to be one-shot and self-contained:

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

To do a call like that Id have to embed a DNS fetcher and an OpenPGP implementation in the library. Which I wouldnt of course; Id 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 couldnt 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

Im 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 Ive said this before, but RFC 4880 is really just fine; when Ive needed to look something up, it was easy to find and easy to understand.

The problem Ive 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 Id like to have exactly three API calls to do those three things. But that wouldnt 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

Theres 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 its signed with,

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

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

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

The second form is a sort of signature computed over the message thats short enough to fit into a tweet or DNS TXT record. Its a Web-safe base64 of a prefix of the SHA-256 digest of the binary bits in the encrypted form of the message. Once youve stripped the ASCII, the codes 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 arent dramatic but theyre kind of fun; the codes 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. Heres 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, youre good.

  • For GitHub: Theres a special API URL you can fetch a plain-text version of the gist from, so you need to be sure that the handle theyre claiming is in the path to it (case-insensitively, sigh), and that its 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 proofs 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: Its probably the hardest. First, using Twitters REST API in an open-source app is essentially impossible, so you have to do HTML scraping. Second, you have to worry about someones @-reply to a proof tweet containing the sig. So I brute-force extract the tweets <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: Its 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 theyre usually right. But boy, would the Java and Android ecosystems ever benefit from a crypto library that doesnt Solve The Whole Problem, but just does OpenPGP messaging and thats all. If I were a young hotshot with a few cycles, Id be thinking seriously about taking that task on.

Thanks!

To Dominik and Vincent from OKC, and Max and Chris from Keybase. Ive learned an enormous amount and had fun doing it, and those guys are all ace.


see the original posting from ongoing

Back to top