
Cryptocat: webchat with client-side encryption features - magikarp
https://crypto.cat
======
dekz
Took me a little while to realise you set the password in the blue box above
the text entry. Interesting concept though.

For those interested it uses crypto-js (<http://code.google.com/p/crypto-
js/>).

Might want to increase the random entropy source, from what I can see it's
just DateTime.

Also I'd use a better hashing algorithm than SHA1 with AES-256.

I understand the need for PBDKF2, but I'm not so sure about using the password
as the key and salt.

~~~
tptacek
They aren't using SHA1; they're using HMAC-SHA1. Not the same thing.

That said: this is an idiosyncratic (rekeying AES every 500ms?) and not
particularly resilient cryptosystem. As a commenter said below: don't use this
for anything serious. You're equally well off with a server that simply sends
"plaintext" messages over TLS.

~~~
magikarp
AFAIK, the server does not rekey AES every 500ms - and your suggestion to use
a server over TLS opens you up to the problem of the server itself being able
to read all plaintext.

~~~
tptacek
The server can read all the plaintext anyways.

~~~
magikarp
No it can't, that's the whole point! Are you trolling?

~~~
tptacek
No, what's happening here is that that you don't actually understand the
threat model for encryption code running in Javascript fed by a server, and
you're getting more and more frustrated by the fact that I'm not handholding
you through it.

Reasoning about security systems (click my name to see that I do that for a
living) is frustrating. To see what's happening in this case, steel yourself
for a headache, sit down, and think hard through all the different things that
attackers can potentially influence. Then ask yourself, "what could an
attacker accomplish by manipulating that thing?".

------
gojomo
Made a test room, 'hn' (<https://crypto.cat/?c=hn>). Set a key, 'password'.
Will leave it open in background and peek in occasionally if others want to
try.

------
cranklin
I was thinking of building something similar. The benefits of client-side
encryption is that the message is entirely encrypted until it reaches the
destination. Even if the cryptocat server was compromised, the message is
still "safe".

~~~
tptacek
No, if the server is compromised, you are thoroughly boned. In fact, there are
very common vulnerabilities that don't come close to compromising the server
that still destroy the security of this scheme.

Javascript cryptography is almost always a terrible idea.

~~~
magikarp
"If the server is compromised [insert disastrous result here]" applies more so
to many other servers serving you crypto - I feel there's the advantage of
being able to verify the .js files yourself in your browser here:

<!-- cryptocat uses the crypto-js library - <http://code.google.com/p/crypto-
js/> \--> <!-- [http://crypto-js.googlecode.com/files/2.3.0-crypto-
sha1-hmac...](http://crypto-js.googlecode.com/files/2.3.0-crypto-sha1-hmac-
pbkdf2-blockmodes-aes.js) \--> <script type="text/javascript"
src="js/crypto.js"></script>

~~~
tptacek
You can't just verify the .js file! You have to verify every line of JS code
that ever hits the JS interpreter, whether it's specified directly in the
source code that the author told you about or eval'd later in some random
event handler. That code could come from an explicit <script> tag in the
original DOM source; it could come from an event handler specified in the DOM,
or set later by any other piece of JS; it could come from an Ajax request
handler; in many browsers, it can even come from CSS. It can easily hide
itself after it does its job, and it isn't going to look like "<!-- zero out
AES key here -->".

The browser JS runtime does not provide the tools you need to verify the
integrity of a cryptosystem. Full stop.

Actually, browser JS runtimes don't even provide the tools you need to safely
_run_ a cryptosystem. How do you know what intermediate values are cached by
any given JS? How do you know if any given crypto function is leaving
footprints in browser memory? You don't; nobody does; nobody has published the
exhaustive analysis of _any_ browser JS to support an argument either way.

Not that that matters for crypto.cat; they don't seem to care much about side
channel stuff; for instance, their HMAC compare is the JS string "!="
operator.

As for "applies to so many other servers": I don't know what you're saying.
You made a claim about the security properties of this application. That claim
was wrong. It doesn't become right when you point out some other app that has
the same flaw.

~~~
deno
What about loading Java applet (and communicating from JS) that handles all
encrypting/decrypting? Would that take care of at least the latter concern?

~~~
tptacek
Yes; you could just use Bouncycastle's Java PGP implementation, which is
probably the safest option.

But people hate Java, and it's increasingly disabled in browsers.

~~~
deno
Well I thought the question was interesting because if that'd work, so would a
native Web API.

~~~
tptacek
A native web API would work! I think it'd be great if everyone could agree on
some basic, high-level crypto functions, implemented in browser C, to expose
to JS. You'd want the interface to look much more like Keyczar than crypto-js,
though.

~~~
deno
I was also wondering — I hope you don't mind — would it be considered safe to
just verify signed messages using cryptojs? For example, let's say the
environment (webapp) is bootstrapped using TLS, this includes the public key.
Now could this application receive signed messages through different, unsecure
channel and verify them safely using the public key received through the
secure channel?

~~~
tptacek
If it can be safe to verify the integrity of a JS cryptosystem at all, I think
it's going to turn out to be tricky to do it. Like I said elsewhere on this
thread, the number of ways a web page can influence the Javascript runtime is
huge, and a lot of those ways are cached.

~~~
deno
Well the integrity of the JS cryptosystem would be no worse than the integrity
of the webapp itself.

I understand that one cannot trust the JS crypto for handling the private key
and doing any singing & encryption because of the possibility of leaking
information through side channels. That's why I was wondering if it'd be
possible to use JS crypto in only one way — that is to verify messages against
public key received through the secure channel.

If the JS crypto only does verification, it wouldn't matter if the _public_
key is cached, as long as it can't be arbitrarily changed by another process.
If the server is taken over or there's an XSS or other client-side
vulnerability the bidirectional TLS would be similarly useless anyway.

~~~
tptacek
It's not the "math" of the crypto that concerns me; it's the actual integrity
of the code performing it. So for instance, if you're trying to do RSA
operations in JS, how do you know that none of the bindings in the current
Javascript runtime have been exposed to attacker-controllable content? How do
you know nothing in the runtime was fed by cached content read over straight
HTTP? Or from an HTTPS server that has a DOM corruption flaw?

~~~
deno
If any of those things can be used to affect the crypto part, then they could
be also used to affect the web application itself, in the first place. I'm
only looking for the level of integrity, that I can get from launching the web
application over HTTPS anyway.

~~~
tptacek
Is this a point that we're dancing around here? Let's resolve it: for the most
part†, you're right: the things that break clientside JS web crypto are things
that break (in various degrees) the web app itself. The problem with accepting
this is that the point of clientside crypto is to inoculate users from the
downside risks of the simple security flaws that most applications have.
What's the point of sophisticated clientside crypto if it's undone by any
trivial XSS flaw?

† _There_ are _issues that damage clientside JS crypto that don't blow up the
app itself, but they are not the core issues I'm concerning myself with here._

~~~
deno
I am mostly interested in replacing bi-directional TLS. There are things that
need to be encrypted — authentication, any authorized operations, fetching
authorized content — however the majority of content that application uses is
public, so the encryption is very much redundant.

Unfortunately I can't just bootstrap the application over secure channel and
fetch any content over not secure channels, as it'd be trivial to then poison
the application using the unencrypted communication. Take a Hacker News-like
application: Let's say that news and comments can be accessed over unsecure
channel and voting and authentication are performed over TLS. Even though the
authorized operations are safe, the data could be poisoned over unsecure
channel — for example the user-id could be manipulated and the user would end
up voting securely for someone else's post. To mitigate it, all data would
have to be fetched over secure channel. However currently this is all or
nothing, by fetching public data over TLS, one has to pay the encryption tax —
in both CPU time, as well as in disabling any caching middleware.

Of course singing HTTP messages wouldn't be just TLS-light, since the messages
could be stored and kept as an evidence that the webserver has produced such a
message, which is different to TLS session-based guarantees, but it should be
fine for what I need. This is why I was interested to know if such an approach
would not degrade the security of the web application below what bi-
directional TLS could offer.

I suppose this is not the most exciting use for client-side cryptography right
now…

I think the web-application are increasingly going in the direction of
reinventing Java applets anyway. There are few components that are needed for
that and that will be gradually introduced: 1) Application that can be
installed and launched locally (e.g. more sophisticated version of Chrome
Webappstore). Once you have that, you basically have RPM in browser. 2)
Capabilities system that controls what and how an application can access. All
the pieces are already in there: web extensions, mobile apps, etc. 3)
Pluggable storage to eliminate the need for storing data on the remote server.
There is LocalStorage and IndexedDB already, now it's just a matter of time
till Chrome adds Google Storage, Apple adds iCloud, Ubuntu adds UbuntuOne etc.

Once you have that, the Java[Script] applets are basically back. With NaCL in
the mix you could even actually run the JVM in the browser once again. So
yeah, I think in the long run the client cryptography will come around. But
for now I just wanted to make use of what's currently available.

~~~
tptacek
This is generally a terrible idea. TLS 1.2 is the product of almost 20 years
of sustained attention and adversarial testing effort, 20 years of missteps,
20 years of design decisions argued over by people clearly not limited to but
including some of the best cryptosystem thinkers in the field, and it _still_
has missteps in it.

The idea of replacing it with ad-hoc encryption at the application layer
carries with it the notion that the basic problem of "taking some bundle of
application data and securing it so that it is encrypted in flight" is somehow
simple, and that TLS 1.2 is overkill for it. But that's not true. To a
significant extent, everything TLS 1.2 does that you don't do is a
vulnerability in your system. You won't see it or fully understand it;
extremely competent people have gone _years_ staring terrible vulnerabilities
in TLS in the face, even after those flaws were _pointed out to them_ , and
let them pass because the real-world practical impact wasn't obvious at the
time.

And this is all before you get to the point where, to avoid the overhead and
complexity and inflexibility (and whatnot) of TLS 1.2, you choose to build
_your_ cryptosystem in the most hostile possible environment for cryptography:
the language runtime where no operation, function, or binding can be trusted,
where every symbol table is potentially corrupted by any of 10s of content
sources, many of them under the control of attackers, in a runtime that is
being aggressively redesigned, optimized, JIT'd, cached, and transformed for
performance.

So you can see that this goal puts you out in the wilderness on _two_ vectors:
one of attempting to start from scratch on secure transport protocols, when 20
years has shown us that the simplest service models for secure transport are
surprisingly hard; and the other vector being "trying to implement secure
crypto in a language environment that's hostile to the concept".

Skip it. Work on something that will make people's lives better in the
immediacy, instead.

~~~
deno
> The idea of replacing it with ad-hoc encryption at the application layer

Yes, I understand that this would be a terrible idea. That is why I only
intended to _verify_ signed, _public_ content using _static_ key. I don't
indent do any encryption in client-side JS, not even to generate session keys!

~~~
tptacek
Verifying signatures under public keys is not an easier problem than
encrypting data; it's actually a harder one: more things can go wrong, not
less.

~~~
deno
What do you mean? I thought if you eliminate any of the things I've mentioned
previously all that is left is just checksum algorithm and some math. Note
that the public key would come from the secure TLS channel, so there's no
issue of obtaining and verifying one.

~~~
tptacek
We're too far to the right on this thread to keep going with this, but take my
word for at least this: public key signature verification is advanced number
theoretic cryptography. It is actually _less_ straightforward than somehow
applying a block cipher to variable-length arrays of user data.

~~~
deno
So does it just mean that the implementation is hard to get right? I'm all for
killing off ideas, especially when it comes to cryptography, but I'd like to
at least learn something in the process. Is there somewhere I can learn about
everything that can go wrong with that specific process, or would I have to
just try to implement this algorithms myself, to understand the risks? BTW.
Thanks for everything so far; I trust you're a busy man.

~~~
tptacek
A great place to start is (Google) [nigel cryptography]; for your particular
question, start with the chapter "attacks on public key cryptography".

------
u48998
Seems useful.

~~~
mtogo
Except that the encryption is handled with javascript (obviously). I wouldn't
use this for anything serious.

~~~
magikarp
Why not? AES has been implemented in javascript half a dozen times.

~~~
tptacek
And? What is that evidence of?

~~~
sorbus
That the implementation of an encryption library in Javascript is not a reason
to mistrust services which use that library?

~~~
tptacek
It isn't evidence of that. Implementation in _browser_ JS _is_ in fact a
reason to distrust a cryptosystem.

