Main menu

Post navigation

Wanted: Native JS Encryption

I’d like to challenge all browser vendors to put together a comprehensive JS API for encryption. I’ll use this blog post to prove why it’s necessary and would be a great move to do so.

The Ultimate Security Model

I consider Mozilla Sync (formerly known as “Weave”) to have the ultimate security model. As a brief background, Mozilla Sync is a service that synchronizes your bookmarks, browsing history, etc. between computers using “the cloud”. Obviously this has privacy implications. The solution basically works as follows:

Your data is created on your computer (obviously).

Your data is encrypted on your computer.

Your data is transmitted securely to servers in an encrypted state.

Your data is retrieved and decrypted on your computer.

The only one who can ever decrypt your data is you. It’s the ultimate security model. The data on the server is encrypted and the server has no way to decrypt it. A typical web service works like this:

Your data is created on your computer.

Your data is transmitted securely to servers.

Your data is transmitted securely back to you.

The whole time it’s on the remote servers, it could in theory be retrieved by criminals, nosy sysadmins, governments, etc. There are times when you want a server to read your data to do something useful, but there are times where it shouldn’t.

The Rise Of Cloud Data And HTML5

It’s no secret that more people are moving more of their data in to what sales people call “the cloud” (Gmail, Dropbox, Remember The Milk, etc). More and more of people’s data is out there in this maze of computers. I don’t need to dwell too much about the issues raised by personal data being stored in places where 4th amendment rights aren’t exactly clear in the US and may not exist in other locales. It’s been written about enough in the industry.

Additionally newer features like Web Storage allow for 5-10 MB of storage on the client side for data, often used for “offline” versions of a site. This is really handy but makes any computer or cell phone used a potentially treasure trove of data if that’s not correctly purged or protected. I expect that 5-10 MB barrier to rise over time just like disk cache. Even my cell phone can likely afford more than 5-10 MB. My digital camera can hold 16 GB in a card a little larger than my fingernail. Local storage is already pretty cheap these days, and will likely only get cheaper.

Mobile phones are hardly immune from all this as they feature increasingly robust browsers capable of all sorts of HTML5 magic. The rise of mobile “apps” is powered largely by the offline abilities and storage functionality. Web Storage facilitates this in many ways but doesn’t provide any inherent security.

Again, I don’t need to dwell here, but people are leaving increasingly sensitive data on devices they use, and services they use. SSL protects them while data is moving over the wire, but does nothing for them once data gets to either end. The time spent over the wire is measured in milliseconds, the time spent at either end can be measured in years.

Enter JS Crypto

My proposal is that there’s a need for native JS Cryptography implementing several popular algorithms like AES, Serpent, Twofish, MD5 (I know it’s busted, but still could be handy for legacy reasons), SHA-256 and expanding as cryptography matures. By doing so, the front end logic can easily and quickly encrypt data before storing or sending.

For example to protect Web Storage before actually saving to globalStorage:

Using xmlHttpRequest or POST/GET one could send encrypted payloads directly to the server over http or https rather than send raw data to the server. This greatly facilitates the Mozilla Sync model of data security.

This can also be an interesting way to transmit select data in a secure manner while serving the rest of a site over http using xmlHttpRequest by just wrapping the data in crypto (that assumes a shared key).

I’m sure there are other uses that I haven’t even thought of.

Performance

JS libraries like Crypto-JS are pretty cool, but they aren’t ideal. We need something as fast and powerful as we can get. Like I said earlier, mobile is a big deal here and mobile has performance and power issues. Intel and AMD now have AES Native Instructions (AES NI) for their desktop chips. I suspect mobile chips who don’t have this will eventually do so. I don’t think any amount of JS optimization will get that far performance wise. We’re talking 5-10 MB of client side data today, and that will only grow. We’re not even talking about encrypting data before remote storage (which in theory can break the 10MB limit).

Furthermore, most browsers already have a Swiss Army knife of crypto support already, just not exposed via JS in a nice friendly API. I don’t think any are currently using AES NI when available, though that’s a pretty new feature and I’m sure in time someone will investigate that.

Providing a cryptography API would be a great way to encourage websites to up the security model in an HTML5 world.

Wait a second…

Sure, both are great, but web apps should be in control of their own security model regardless of what the terminal is doing. Even if they are encrypted, that doesn’t provide a great security model if the browser has one security model in place for Web Storage and the site has its own authentication system.

Don’t JS Libraries already exist, and isn’t JS getting the point of almost being native?

True, libraries do exist, and JS is getting amazingly fast to the point of threatening native code. However crypto is now being hardware accelerated. It’s also something that can be grossly simplified by getting rid of libraries. I view JS crypto libraries the way I view ExplorerCanvas. Great, but I’d prefer a native implementation for its performance. These libraries do still have a place bridging support for browsers that don’t have native support in the form of a shim.

But if data is encrypted before sending to a server, the server can’t do anything with it

That’s the point! This isn’t ideal in all cases for example you can’t encrypt photos you intend to share on Facebook or Flickr, but a DropBox like service may be an ideal candidate for encryption.

What about export laws?

What about them? Browsers have been shipping cryptography for years. This is just exposing cryptography so web developers can better take advantage and secure user data. If anything JS crypto implementations likely create a bigger legal issue regarding “exporting” cryptography for web developers.

A first step would be to have a big num implementation available in js, with the associated big num API.
Some, not all but some at least, crypto algorythm could be fast in js just by virtue of having a fast big num implementation available. I just suggested to Relya how a few minor change to the mp_int API hidden inside NSS (make a dozen functions frozen and public, add two new functions for creating/destructing a mp_int object) would make it possible to implement such an API with js-ctypes, without any further native component. But Relya is very reticent to any crypto outside NSS.

Having native crypto APIs exposed to JavaScript makes such obvious sense to me. I’ve played about with creating a library that implements JS encryption on top of local storage, but it’s far from ideal (see https://github.com/ahume/smart-storage).

Key storage seems like the biggest problem. Each client needs a key to identify itself. That key needs to live on the client. And without an extension like Weave^WFirefox Sync, how do you do that securely?

Ideally I’d like to see more widespread use of client certificates, but that doesn’t necessarily solve the whole problem.

@Patrick Mueller: The key is essentially your password, you’d most likely want to prompt the user to unlock their data, just like you would in any other implementation. If you store your password, it’s not secure.

This doesn’t really change anything security wise, except encourage web developers to encrypt data on the client side. Best practices all still apply.

There’s one weak part in Sync, the fact it uses J-PAKE
It’s hard to believe how much Brian Smith resisted my suggestion that J-PAKE was the wrong choice for Sync, and that SRP should be used instead.
This is all clearly explained here : http://rdist.root.org/2010/09/.....to-tlssrp/
(the writer of the JPAKE patch in OpenSSH explains there you should not use it !)

I didn’t have a clear idea at the time of that discusion with Brian what the J-PAKE patch would look like, but now that I’ve seen the result it’s obvious it’s so similar to SRP than converting from one to the other is really easy, at the very least much less work than writing the whole J-PAKE patch.
Even if you need the algo in balanced instead of augmented mode, it’s real easy to use SRP in a balanced mode (you just have to make the server generate the verifier on the fly every time from the password, using the same call the user normally just runs once for all to do it).

My group at Stanford have a pretty fast JS crypto library called SJCL (see website). Sure, it’s still a library, and it’s nowhere near native speed. But it can do 1-1.5 MB/s (depending on mode) of AES, including marshaling, unmarshaling and authentication, on my 1.6GHz laptop. It also does SHA256 hashing, HMAC, and elliptic curve public key encryption/signatures. This might be good enough for an app doing offline storage, at least on the desktop/laptop.

Also, you should limit the amount of legacy/nonstandard stuff here. AES modern modes and SHA256 are sufficient. Maybe add a legacy mode like AES-CBC so that it’s easier to interact with on the server side. There’s no point in adding Serpent, Twofish and especially MD5.

The example seems fatally flawed to me. Aren’t you getting all the JS from the webapp from a web server that you claim not to trust? If you trust them to deliver JS to you (that does the encryption) why not just use SSL and trust them to encrypt at their end?

@Erik: You missed the point. Client side encryption isn’t so much about protecting in transit (though theoretically possible), it’s about protecting end to end. If a server encrypts, it can decrypt, that’s a single point of failure. If the client encrypts and is the only one to know the key, the server is just storage.

web apps should be in control of their own security model regardless of what the terminal is doing.”

I disagree. The average random web developer is far more likely to screw things up than the ssl implementor. Cryptographic schemes only have to be slightly screwed up to be made useless. Heck, even sony couldn’t get it right when they were doing what’s probably the most important piece of cryptographic code in their career.

And this being on the web in javascript, the client side code will in most cases be visible to all, and screwups will be obvious to an expert with malicious intentions.

@Robert: That’s the point. Cryptography should be done by the browser, not JS libraries. I just want cryptography to be readily accessible so it can be implemented by web developers. SSL only protects data in transit. Not at either end.

If you don’t completely trust the server (in fact all servers that provide any html or js content to your page), how can you trust that somewhere in the webpage someone hasn’t inserted a tiny little extra script tag: