- From: Vijay Bharadwaj <Vijay.Bharadwaj@microsoft.com>
- Date: Sat, 30 Jun 2012 07:14:19 +0000
- To: Zooko Wilcox-OHearn <zooko@leastauthority.com>, "public-webcrypto@w3.org" <public-webcrypto@w3.org>
I agree with 2. I disagree with the characterization of 3, and I don't think that is what is intended at all. I believe 3 is about recognizing that a lot of the security of real systems comes from an interesting interplay of software and physical-world constructs, and trust is derived from some sort of ceremony that ensures robustness against bad behavior both by actors in the protocol as well as components of the computer systems involved. For instance the reason people hand out chip-and-PIN credit cards and banking dongles with LCD displays is because the only things that are truly trusted are the human endpoints (bank and customer). These are trusted not because of some technical or idealistic reason, but because if they misbehave there is some strong well-understood non-technical (typically legal) recourse available to the other party. Everything else, including the computer, web browser, etc., is suspect and must be protected against. Therefore this category of things is about recognizing that web browsers are a hostile environment, and providing a way for humans to achieve some assurance of security in the face of this reality by taking the security perimeter outside the vulnerable client system. For the set of situations where the transaction being protected is of sufficient value, I believe this protection is worth providing. In other words, the interesting part of 3 to me (and as represented by the "smart card" use cases) is not about "using code from foo.com to encrypt data against foo.com" but about giving foo.com the ability to serve code to me that, when used with a physical artifact also given to me by foo.com, ensures that I can for example sign messages to foo.com that are assuredly from me and not from the gremlins between me and foo.com. If the gremlins try to play tricks with the code from foo.com, it will lead to some easily-recognizable effect that will give me pause (e.g. my browser says I'm transferring $20 but the LCD on my bank-issued dongle says $2000). Separation of origins IMO is an orthogonal issue, and is related to privacy concerns rather than cryptographic security in the traditional sense. It just happens to only show up in cases where one has persisted keys that survive across user sessions. Of the use cases that Brian cites, I believe that except for the mod-exp bits they all fall within category 2. There's nothing wrong with that, but we shouldn't lose track of the various valuable cases that don't fall in that bucket. -----Original Message----- From: Zooko Wilcox-OHearn [mailto:zooko@leastauthority.com] Sent: Friday, June 29, 2012 2:55 AM To: public-webcrypto@w3.org Subject: taxonomy and use cases Folks: Please read the following letter. The author, Brian Warner, has been my partner for the last six years in designing and implementing Tahoe-LAFS ¹ (which makes an appearance toward the end of this letter), and he has written exactly what I wish I had written about the general topic of crypto in Javascript. Reading this letter from him helps me understand why I'm so little interested in the "wrapping and identifying keys" features. Of the three kinds of crypto-in-JS in Brian's taxonomy -- 1. fast math, 2. primitives, 3. separation of authority on the web -- it sounds like our WG is trying to standardize both 2 and 3. Kind 3 seems to be inapplicable to most of my use cases, which is why I'm keen to see kind 2 standardized well. By the way, I disagree with Brian when he writes that it is not worth designing a system which can run code from foo.com on user data while preventing foo.com from accessing that data. I think that is currently impossible, but will be possible in the future (by the addition of new UI in the web browser that allows users to see and control which versions of the code from foo.com get run). Regards, Zooko ¹ https://tahoe-lafs.org === Crypto-in-Browser Taxonomy --- Brian Warner --- warner@mozilla.com There are several different runtimes I'm interested in targetting (DOMCrypt itself might not address all of them, but it'd be nice to have an API that's good for all three): * web content (the usual page environment) * addons / chrome code * Node.js And I'd like to split out potential features into three separate categories: this might make it easier to argue about the details: A: fast math for Javascript B: correct implementations of standard/common cryptographic algorithms C: separation of authority: content-vs-browser, origin-A-vs-origin-B Category A (fast math) is about adding real integers, maybe bignums, native-code constant-time modular-exponentiation functions, and proper mutable bytes/UInt8Array types (with bit-shifts and XOR). This would make it possible for crypto developers (i.e. the authors of Crypto++ or Botan or SJCL) to implement any algorithm in JS without going through the numeric contortions currently required (like using 52 bits of each float, depending on the browser). This is clearly just about JS the language, independent of where it's being run. I'd want to include a better entropy source in this category, even if it's really coming from a DOM-ish place like window.crypto, because it feels like a fundamental tool that really needs to come from the platform (ala /dev/urandom). Category B starts at the bottom of the stack with primitives for AES, SHA256, RSA, etc. Higher up this stack are simpler (less footgun-prone) "box/unbox" -style methods, like the ones exposed by the "crypto_secretbox" functions in http://nacl.cr.yp.to/secretbox.html . Again, these are just providing quality implementations of useful algorithms for Javascript, and are independent of the runtime environment. If we had fast math, we could probably build these out of pure JS, but it might be faster to build them with native code, and safer to provide a pre-packaged well-reviewed implementation than to hope developers will find the right library. Every function in this category is handed the raw key material that it needs as an argument. Having low-level primitives would enable crypto-savvy developers to build two things: new high-level tools, and applications which are compatible with existing deployed protocols. High-level tools are safer for less-savvy developers, but less flexible. Even if we only had code for categories A and B, it'd be a big win. We'd have tools to use quite safely in the addon/chrome/Node.js world. We'd also have tools to let foo.com give me web-page code with which we could encrypt data against observation by bar.com. Category C (separation of authority) is where it gets fuzzy. This part is about hiding the key material inside some box, and giving access to "sign" or "decrypt" methods on the box but not revealing the real keys. It's also about controlling invocation according to the origin of the code doing the sign/decrypt call. It makes slightly more sense to do this with the high-level tools (box/unbox) than with e.g. low-level AES, so I think the discussion sometimes assumes that "high-level" means "separated-authority", when really they're orthogonal. Some people think that there's no point to writing any crypto code that doesn't provide category C. I think this argument depends upon two assumptions: "web content is the only interesting runtime environment", and "encrypted data produced by code that came from foo.com will only ever be sent back to foo.com". Both used to be true (before Node.js, JS-based addons, or CORS/cross-domain-XHR), but are now false. The purpose of third part, in my mind, is to introduce a form of revocation: rather than having code generate raw key material directly, it asks the implementation to create keys trapped inside some module boundary and return to it a handle through which those keys can be exercised. The handle (which could be represented by a special JS object, or just an index number) is only useful in certain JS environments (maybe only web-pages loaded from the same origin as the code which created those keys). This code can't leak the raw keys (which would be irrevocable), but it can sign/decrypt on behalf of other parties (until it gets shut down). In some cases, the human user will be involved in managing this sign/decrypt authority: some of the proposals add UI, where the user is asked to approve an action (initiated by web-page content and satisfied by chrome-side code). They might also be asked to provide a secret (like a master password, to unlock the other keys). The user needs to be given enough information to make this an informed decision, so the usual issues apply (having a trusted path to the browser chrome that can't be spoofed by web content, having recognizable petnames to identify origins, etc). Introducing controls like this may improve safety on some fronts, but also reduce flexibility on others, and presumes certain use cases more than others (the first two categories are pretty use-case-agnostic). Note that the first two parts are already implemented in various ways, like SJCL, (even if they aren't as efficient or well-reviewed as we'd prefer). It's the authority-separation stuff which requires changes to the environment. Finally, a note about the "use code from foo.com to encrypt data against foo.com" case. There's a strong argument that this is pointless: foo.com can easily (and mostly undetectably) serve you alternate code which reveals your secrets to them. Keeping the actual key secret and exposing an encrypt/decrypt method is marginally better: you can revoke access to the key, but only after you discover that they're abusing it. Code on a web page can change every time you hit that URL. Code in a native application is still mutable, but it doesn't usually change quite so frequently (most apps still have noisy user-visible update processes, but we're slowly moving to the web model where updates occur silently and without user approval). I think there's a spectrum here, from slow-moving fundamental code (OS kernel, browser) to fast-moving load-each-time maybe-cache-it code (web pages). The important metric is: if the provider of the code wanted to make you run a malicious version, how easily could they do it, and are they likely to get caught? Imagine that all app upgrades were cross-checked against a dozen of your friend's copies, and published in some uncensorable way, before being applied. Now a app vendor who sneaks some leak-your-key change into your copy of the code would probably be caught when 1: your app warns you when it notices that it's installing an upgrade that nobody else has seen, and 2: the world can decompile the code you were asked to install and present evidence of the attack. If the app vendor's reputation is important to them, they'll be disincentivized to attempt this sort of attack. When the code in question is open-source, we can pretend that some users will examine the code for each upgrade, compile it themselves, then run only their own trusted copy. Anyone who takes shortcuts (i.e. most everyone) will be vulnerable to the same things described above. The notion of simultaneously trusting a person enough to give their code access to your secrets, while not trusting the person with the secrets themselves, is a little bit crazy. For this to be rational, they must have some strong incentives to always give you good code. If you don't think you can distinguish between foo.com and the code they gave your browser, is there any point to doing the crypto in the browser and not on foo.com's servers? If the data being used lives on the browser, then I think there are two performance wins: local crypto will be faster (no roundtrips), and spending CPU cycles at the edges instead of on the server means less competition (user incur their own CPU costs, instead of contending with other users for server-side CPU time). But I'm really interested in the use case where I work with foo.com (and the code they serve me) to encrypt data in a way that protects me against the actions of bar.com . Think of foo.com as a web-app provider and bar.com as a bulk-storage service. If we can do that, then we can develop other tools to help protect me against foo.com: we might include content hashes in URLs (so my bookmark is enough to verify that I'm getting the reviewed version of the webapp), or I might locally cache the app for a long time, or the app might actually be served by a locally-trusted agent. Finally, the use-cases I'm interested in are things like: * http://tahoe-lafs.org in a Firefox addon and/or Node.js module. For this, I need AES-CTR, SHA256, RSA signatures, and eventually ECDSA signatures. I don't need authority separation. If it were Tahoe-like and didn't have to be compatible with Tahoe itself, I'd be delighted to just have djb's NaCl. * http://hg.wearpants.org/wherestheparty (web content). In this project, code from one domain needs to to verify a signature (e.g. ECDSA) on data coming from a different domain, using a pubkey embedded in data from the first. Signing is done offline. It might also want to decrypt resources coming from the second domain before displaying them. * Code to perform key negotiation (OTR-style) and data encryption for real-time messaging (secure IM) over websockets or WebRTC. Initially it could be done in web-content (still vulnerable to the code provider), but could migrate to an addon. Needs DH (curve25519 would be great), AES (in some authenticated-encryption mode), or just some high-level box/unbox primitives. * Code to do anonymous-remailer operations like Sphinx (http://eprint.iacr.org/2008/475) and the Pynchon Gate (http://www.freehaven.net/anonbib/cache/sassaman:wpes2005.pdf): mostly symmetric operations plus a few modular-exponentiations. * Code to do PAKE, which usually needs mod-exp, DH key-agreement, and zero-knowledge proofs of x given g^x. -- Regards, Zooko Wilcox-O'Hearn Founder, CEO, and Customer Support Rep -- Least Authority Enterprises https://leastauthority.com
Received on Saturday, 30 June 2012 07:15:08 UTC