No I didn't use the Web Crypto Api
Recently I've done a deep dive into Node crypto, including implementing a large portion of it in the browser for Browserify.
In future blog posts, I'll likely cover the intricacies involved in implementing getCipher, createDiffieHellmann, getSign/getVerify and getECDH. But to start out, I'll cover the question I get most often.
Did you use the Web Crypto API?
The answer is not really, only the random number generator. And I don't see myself using much more.
The number one reason is just that it is totally async, while the Node one is mostly synchronous. I did look into it for PBKDF2, which is async in Node and doesn't seem ready for production.
First off, when people talk about Web Crypto, they are talking about a couple APIs defined in this spec.
The random number generator (crypto.getRandomValues) is pretty widely implemented and easy to use; the rest of the API is namespaced under subtle because the methods it contains have "subtle" intricacies to avoid them being footguns. Or to quote the spec:
It is named SubtleCrypto to reflect the fact that many of these algorithms have subtle usage requirements in order to provide the required algorithmic security guarantees.
The SubtleCrypto API has very patchy support browser-wise. Firefox and Chrome both implement parts of it, but different parts, and it's hard to tell which ones. Internet Explorer implements it without using promises for the async aspects (bear in mind it is all async), so for all intents and purposes they may as well have implemented some other spec. As for Safari, who knows that the hell they are up to.
The last and biggest issue is that the API does so much, but also somehow very little. Take a look at the succinct syntax for PBKDF2 in Node:
https://gist.github.com/calvinmetcalf/37fe1d4fefe28c8ce98c
(In Node v0.11, the digest algorithm is optional and defaults to SHA1. In previous versions it couldn't be specified).
Now compare that to SubtleCrypto:
https://gist.github.com/calvinmetcalf/7bc5dd44770eb163e018
(Note that this only works on Firefox, and if you specify a different digest algorithm it explodes with a vague error.)
What is SubtleCrypto actually doing?
First we have to import our "key"; the arguments this takes are: what type of key we are importing (in this case raw, which means not actually a key), followed by the "raw key" (a.k.a. what we want to use with PBKDF2), followed by an "algorithm object" specifying what algorithm we want to use with the key once we import it. This is followed by a boolean specifying whether the key is exportable and a listing of methods that are approved to use the key, so if we wanted to use the key with another SubtleCrypto method we'd need to specify deriveKey instead of deriveBits for the allowed algorithm. It's async and returns a promise, and all arguments are required.
All this, to take a string and turn it into a form appropriate for PBKDF2, an algorithm that takes a string as input.
Then deriveBits takes a PBKDF2 object like the one you gave to importKey, except with a bunch more fields including iterations and salt, as well as digest identifier (not an algorithm object, but an algorithm identifier for some reason). In addition to the algorithm object, it then takes the same key from before and the output key length.
Fundamentally the API is built around key objects, which in theory can be managed by the user agent. The idea is that when somebody types a password into a form, the password can immediately get wrapped into a key object that is non-extractable and can only be used to derive a key or bits, or a plugin like LastPass could store passwords and provide them to the browser in that format. This will be all well and good when that actually happens, but in the meantime we have an absurdly complex spec with complex features, implemented with the hope that venders will implement stuff using it.
This feels like the IndexedDB API (and be aware that is not a compliment). IndexedDB has a maddeningly hard to pin down level of abstraction that is higher-level than something like LevelDB and lower-level then something like SQLite3, and in the end manages to be both extremely complex and extremely low-powered with a massive number of ways to use it wrong.
Things that would make the API much better
Here are a few improvements I would propose for SubtleCrypto:
A getAlgorithms method and an algorithmInfo method. The API is intentionally neutral about what it's going to support, and if I can't know what my browser should do from reading the spec, then that means I need to be able to figure it out from inside the browser. This includes other info, like which hash functions PBKDF2 and HMAC take.
While the key object idea is fantastic, it isn't actually useful now, and in theory may never be useful (think of that second parameter to history.pushState). Designing the API in a way that accepts complex key objects doesn't prevent the API from also accepting buffers or strings and doing sensible things with them.
There is no streaming interface for encryption. Even in the absence of implementing the actual stream spec, the ability to incrementally encrypt data is extremely useful and a feature of most encryption libraries.
The whole Heartbleed fiasco underscores the problems with a "subtle" approach to crypto. The mythical crypto experts that know what they are doing and can correctly configure an algorithm to be unexploitable are not the people setting up servers and running web apps. If there is a way to use a crypto library wrong, people will use it wrong. A strong argument could be made that what the web needs is something more along the lines of NaCL, a library that requires effort to use incorrectly.
Notes:
A big thanks to my company AppGeo; much of this research grew out of an effort we've been making to secure our apps.
Lastly if you're curious about my lack of posts recently, it's because I couldn't bring myself to bump the blog post about Kublai off the front. It's still not really ready, but I've got too many opinions to keep inside.
Edit: Spelling and grammer help from @nolanlawson.





