This content was originally posted as a Twitter Thread. Copied here for archive purposes. Please, forgive potential typos and the succinct writing style.
It’s almost 2019, most of us have access to modern mobile hardware but aside from platform services such as Apple/Google Pay and Local Authentication (FaceID/Fingerprints) there’s still a shortage of sound crypto for handling secrets on the client-side. Don’t get me wrong, we have good crypto out there, but it’s still hard to effectively leverage the full capabilities of end user hardware, particularly at scale. Let’s examine the current situation for iOS, Android and Browsers.
iOS has generally the best posture here. It was quite early that Apple realized developers need to store sensitive data on devices. They came up with Keychain and Secure Enclave, but unfortunately in my humble opinion they failed miserably to provide a friendly API. At least they have long and verbose flags.
Also implementing common use cases such as verification of challenge signature done within the Secure Enclave is not straightforward. In some cases exported public keys are not compatible with OpenSSL
Apple even refused to document which specific cipher suite they were using. A real bliss to implement right?
All this led to the proliferation of “Githubish” boilerplate code that is hard to pick for your products at scale (can I trust the maintainers in the long run?)
An unexpected quick could be found down the road which forced you to send a pull-request and cross your fingers while you wait for support. But, all in all, iOS is in good shape thanks to default Keychain data protection structure, which relies on your device passcode.
Handling secrets on Android looks much more bleak in comparison for products at scale. All because of the well-known device fragmentation. First, contrary to what the term “Android Keystore” (AKS) suggests, you cannot actually store anything there. You can ask it to generate keys and keep them stored there, but that’s it.
Actually, they eventually realized this was a needed feature and recently implemented the feature for importing your own keys.
Still not getting an storage for secrets of arbitrary format (such as an API key or refresh token) though. Lots of blog posts ensued about a seemingly mundane security feature.
Second, AKS was a mess until Android M arrived. Attempts to use it created serious UX problems for disappearing keys after user switched lockscreen credentials or removed them altogether.
After Android M, keystore was more stable and more feature rich by supporting symmetric keys generation which are more convenient for protecting custom secrets at rest. Still, you face the problem of fragmentation. Your code needs to gracefully handle different API Levels and OTA updates transitioning through feature availability borders. Too much complexity and moving parts for products at scale.
Developers just ended up ditching the AKS for more mundane solutions that just derive keys from regular providers which are not hardware backed. You pay 800e for a phone with an advanced HSM and apps just derive keys on userland using static device ids as seeds. Great.
Can’t blame the guys though. They have enough work trying to dodge landmines from StackOverflow which include insecure code snippets.
As with iOS, Android has its own share of Githubish solutions to wrap around AKS low level API. They rarely actually use AKS to protect secrets at rest. This comment gives the reasons behind this behavior.
And regarding Browsers, Web Crypto API is your chance to prevent key exposure on userland code (JS), but still needs to keep an eye on legacy user support matrix.
The problem of a lost or stolen device (laptop) persists. Are keys protected in an independent secure environment? (SE, TPM, TEE…) This was left as implementation-dependent…
Again, put on the shoes of any developer, why bothering with dealing with this fragmentation mess for an app that operates at scale? Just not worth it.